1
0
Fork 0

Merging upstream version 22.2.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 21:29:39 +01:00
parent b13ba670fd
commit 2c28c49d7e
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
148 changed files with 68457 additions and 63176 deletions

View file

@ -1,6 +1,164 @@
Changelog
=========
## [v22.1.1] - 2024-02-29
### :sparkles: New Features
- [`1e25ec9`](https://github.com/tobymao/sqlglot/commit/1e25ec984510a1ffee76956b0dcb15bcd84f5d44) - **test**: handle NULL value in TPC-DS *(PR [#3052](https://github.com/tobymao/sqlglot/pull/3052) by [@fool1280](https://github.com/fool1280))*
- [`ad21b6b`](https://github.com/tobymao/sqlglot/commit/ad21b6b47716d394ca6b8fb3b82d58b887d5adb3) - **test**: add more passing tpc-ds test *(PR [#3053](https://github.com/tobymao/sqlglot/pull/3053) by [@fool1280](https://github.com/fool1280))*
### :bug: Bug Fixes
- [`08249af`](https://github.com/tobymao/sqlglot/commit/08249af50351a24277e1f3f1574629eb5c68d3a5) - Hive UnixToTime regression, README stale results *(PR [#3055](https://github.com/tobymao/sqlglot/pull/3055) by [@VaggelisD](https://github.com/VaggelisD))*
- [`39b3813`](https://github.com/tobymao/sqlglot/commit/39b381341fe697ae54f5d3a438b4035447fe552a) - **redshift**: don't pop recursive cte table columns *(commit by [@tobymao](https://github.com/tobymao))*
- [`6a9501f`](https://github.com/tobymao/sqlglot/commit/6a9501f7407be3682ce3b9cc73b7340ad9a0c2e8) - ensure UDF identifier quotes are preserved *(PR [#3057](https://github.com/tobymao/sqlglot/pull/3057) by [@georgesittas](https://github.com/georgesittas))*
## [v22.1.0] - 2024-02-29
### :sparkles: New Features
- [`6393979`](https://github.com/tobymao/sqlglot/commit/63939796b39c69b25adfc6f224ccd4761f23cb66) - **oracle**: connect_by_root closes [#3050](https://github.com/tobymao/sqlglot/pull/3050) *(commit by [@tobymao](https://github.com/tobymao))*
### :bug: Bug Fixes
- [`bd0a40d`](https://github.com/tobymao/sqlglot/commit/bd0a40dde2ab2ad168ada0d5bae0c99fba9d762f) - normalize column for lineage and raise if cannot find closes [#3049](https://github.com/tobymao/sqlglot/pull/3049) *(commit by [@tobymao](https://github.com/tobymao))*
## [v22.0.2] - 2024-02-28
### :sparkles: New Features
- [`51f8d58`](https://github.com/tobymao/sqlglot/commit/51f8d5897b18e6f7c0bc66881a3e36c8842ff2ff) - **tsql**: add support for OPTION clause, select only *(PR [#3025](https://github.com/tobymao/sqlglot/pull/3025) by [@nadav-botanica](https://github.com/nadav-botanica))*
- [`c9eef99`](https://github.com/tobymao/sqlglot/commit/c9eef99b8fe3367c22a8186fb397ad550ac11386) - Support for TRUNCATE TABLE/DATABASE DDL *(PR [#3026](https://github.com/tobymao/sqlglot/pull/3026) by [@VaggelisD](https://github.com/VaggelisD))*
- [`703b878`](https://github.com/tobymao/sqlglot/commit/703b87816c3e5f7b50407d2f2a14f3a9cba4e3f8) - **mysql**: add LOCK property, allow properties after ALTER TABLE *(PR [#3027](https://github.com/tobymao/sqlglot/pull/3027) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#3020](https://github.com/tobymao/sqlglot/issues/3020) opened by [@samotarnik](https://github.com/samotarnik)*
### :bug: Bug Fixes
- [`bc4acb9`](https://github.com/tobymao/sqlglot/commit/bc4acb9582a80a6c3d4b491b48a68f110e399e3a) - allow trailing comma in ORDER BY list *(PR [#3031](https://github.com/tobymao/sqlglot/pull/3031) by [@georgesittas](https://github.com/georgesittas))*
- [`4105639`](https://github.com/tobymao/sqlglot/commit/4105639ddbbc504d4bd4607511ac35e8ca30c774) - **bigquery**: unquoted project-0.x closes [#3029](https://github.com/tobymao/sqlglot/pull/3029) *(commit by [@tobymao](https://github.com/tobymao))*
- [`f1f2aec`](https://github.com/tobymao/sqlglot/commit/f1f2aecb09c6c0d9a965d87669368945abd112cc) - bigquery edgecase *(commit by [@tobymao](https://github.com/tobymao))*
- [`5c01c01`](https://github.com/tobymao/sqlglot/commit/5c01c010348271e8cfddea3ed0ac51293c3819b3) - handle falsey values for replace_placeholders kwargs *(PR [#3036](https://github.com/tobymao/sqlglot/pull/3036) by [@sarchila](https://github.com/sarchila))*
- [`ccfbb22`](https://github.com/tobymao/sqlglot/commit/ccfbb2238131bda8fc7a3ad8a9c50a0f009dac52) - **clickhouse**: make CTE expression parser more flexible fixes [#3038](https://github.com/tobymao/sqlglot/pull/3038) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`30e0bb1`](https://github.com/tobymao/sqlglot/commit/30e0bb13162e75c53b031bbb69c66093f8ad4a96) - another edge case *(commit by [@tobymao](https://github.com/tobymao))*
- [`0d93852`](https://github.com/tobymao/sqlglot/commit/0d938524a618b4bd7c057623a2c8755ca3afec6d) - **oracle**: handle GLOBAL/PRIVATE keyword in temp table DDL *(PR [#3045](https://github.com/tobymao/sqlglot/pull/3045) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#3037](https://github.com/tobymao/sqlglot/issues/3037) opened by [@gforsyth](https://github.com/gforsyth)*
- [`e89d38d`](https://github.com/tobymao/sqlglot/commit/e89d38ddd5f699f2ac09baf77238ad5fab00acb8) - **duckdb**: recognize ENUM as a type *(PR [#3044](https://github.com/tobymao/sqlglot/pull/3044) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#3043](https://github.com/tobymao/sqlglot/issues/3043) opened by [@joouha](https://github.com/joouha)*
- [`4db7781`](https://github.com/tobymao/sqlglot/commit/4db77816a44652b3edc8aae5aab24242854f9a14) - avoid raising a KeyError in the lineage module, log a warning *(PR [#3048](https://github.com/tobymao/sqlglot/pull/3048) by [@georgesittas](https://github.com/georgesittas))*
### :recycle: Refactors
- [`5337980`](https://github.com/tobymao/sqlglot/commit/53379805454f0e6f325581b839d2fcb37c10de1b) - simplify parsing of keyword sequences as Vars *(PR [#3034](https://github.com/tobymao/sqlglot/pull/3034) by [@georgesittas](https://github.com/georgesittas))*
- [`bc35c59`](https://github.com/tobymao/sqlglot/commit/bc35c59004cb3fb9849f0ee8e5f06b356396c0b0) - use _parse_var_from_options for USE statement parser *(PR [#3035](https://github.com/tobymao/sqlglot/pull/3035) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`c0d355a`](https://github.com/tobymao/sqlglot/commit/c0d355a27d86539dfd95a87fea7e1bd75c4fabe4) - bump sqlglotrs to 0.1.2 *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v22.0.1] - 2024-02-26
### :bug: Bug Fixes
- [`e2fc6e8`](https://github.com/tobymao/sqlglot/commit/e2fc6e88dc7ae52d956dd84721de197c6c698d90) - **optimizer**: fix parent mutation of new_projections in column qualifier *(PR [#3030](https://github.com/tobymao/sqlglot/pull/3030) by [@georgesittas](https://github.com/georgesittas))*
## [v22.0.0] - 2024-02-26
### :boom: BREAKING CHANGES
- due to [`2507aa2`](https://github.com/tobymao/sqlglot/commit/2507aa2dbad3304304558565f266a7f94acd9e98) - consolidate Subqueryable and Unionable into Query expression *(PR [#2992](https://github.com/tobymao/sqlglot/pull/2992) by [@georgesittas](https://github.com/georgesittas))*:
consolidate Subqueryable and Unionable into Query expression (#2992)
- due to [`d5eb2b1`](https://github.com/tobymao/sqlglot/commit/d5eb2b1e0907026e6e981a8f453f747cb16f44d6) - make implicit unnest syntax explicit by using UNNEST calls *(PR [#3005](https://github.com/tobymao/sqlglot/pull/3005) by [@georgesittas](https://github.com/georgesittas))*:
make implicit unnest syntax explicit by using UNNEST calls (#3005)
- due to [`238f9aa`](https://github.com/tobymao/sqlglot/commit/238f9aa7c32037d0c280cfe6ece77eed9c311cc5) - refactor structs to always be aliases *(PR [#3017](https://github.com/tobymao/sqlglot/pull/3017) by [@tobymao](https://github.com/tobymao))*:
refactor structs to always be aliases (#3017)
- due to [`06bcfcd`](https://github.com/tobymao/sqlglot/commit/06bcfcdf69f850693d941675bbcfce1aa80482f6) - select expressions not statements closes [#3022](https://github.com/tobymao/sqlglot/pull/3022), statements can be parsed without into *(commit by [@tobymao](https://github.com/tobymao))*:
select expressions not statements closes #3022, statements can be parsed without into
- due to [`1612e62`](https://github.com/tobymao/sqlglot/commit/1612e622bd3514d9ca366837f47452969e5267d8) - Add reference to lineage node *(PR [#3018](https://github.com/tobymao/sqlglot/pull/3018) by [@vchan](https://github.com/vchan))*:
Add reference to lineage node (#3018)
### :sparkles: New Features
- [`e50609b`](https://github.com/tobymao/sqlglot/commit/e50609b119c65407f4f7fe27f06510187dc750a0) - Supporting RANGE <-> GENERATE_SERIES between DuckDB & SQLite *(PR [#3010](https://github.com/tobymao/sqlglot/pull/3010) by [@VaggelisD](https://github.com/VaggelisD))*
- [`1709ec2`](https://github.com/tobymao/sqlglot/commit/1709ec2519edc4b1a91f435d76f1b962355be326) - bigquery e6s format *(commit by [@tobymao](https://github.com/tobymao))*
- [`17e34e7`](https://github.com/tobymao/sqlglot/commit/17e34e79d22e3c8211f1bf42047d4ed3557628b6) - add unnest type annotations *(PR [#3019](https://github.com/tobymao/sqlglot/pull/3019) by [@tobymao](https://github.com/tobymao))*
- [`efdbc12`](https://github.com/tobymao/sqlglot/commit/efdbc127a06b1c6204327caa0d6b0cb01590da13) - clickhouse prewhere closes [#3024](https://github.com/tobymao/sqlglot/pull/3024) *(commit by [@tobymao](https://github.com/tobymao))*
- [`1612e62`](https://github.com/tobymao/sqlglot/commit/1612e622bd3514d9ca366837f47452969e5267d8) - Add reference to lineage node *(PR [#3018](https://github.com/tobymao/sqlglot/pull/3018) by [@vchan](https://github.com/vchan))*
- [`5c3bd10`](https://github.com/tobymao/sqlglot/commit/5c3bd1074960874b4557b13df6d30782fe7b0757) - **test**: add more passing tests of tpc-ds *(PR [#3016](https://github.com/tobymao/sqlglot/pull/3016) by [@fool1280](https://github.com/fool1280))*
### :bug: Bug Fixes
- [`7f547e6`](https://github.com/tobymao/sqlglot/commit/7f547e641f7a0ecaa804d5bea14bd24abce1d346) - it's actually seconds + fraction *(commit by [@tobymao](https://github.com/tobymao))*
- [`238f9aa`](https://github.com/tobymao/sqlglot/commit/238f9aa7c32037d0c280cfe6ece77eed9c311cc5) - refactor structs to always be aliases *(PR [#3017](https://github.com/tobymao/sqlglot/pull/3017) by [@tobymao](https://github.com/tobymao))*
- :arrow_lower_right: *fixes issue [#3015](https://github.com/tobymao/sqlglot/issues/3015) opened by [@wizardxz](https://github.com/wizardxz)*
- [`06bcfcd`](https://github.com/tobymao/sqlglot/commit/06bcfcdf69f850693d941675bbcfce1aa80482f6) - select expressions not statements closes [#3022](https://github.com/tobymao/sqlglot/pull/3022), statements can be parsed without into *(commit by [@tobymao](https://github.com/tobymao))*
### :recycle: Refactors
- [`2507aa2`](https://github.com/tobymao/sqlglot/commit/2507aa2dbad3304304558565f266a7f94acd9e98) - consolidate Subqueryable and Unionable into Query expression *(PR [#2992](https://github.com/tobymao/sqlglot/pull/2992) by [@georgesittas](https://github.com/georgesittas))*
- [`d5eb2b1`](https://github.com/tobymao/sqlglot/commit/d5eb2b1e0907026e6e981a8f453f747cb16f44d6) - make implicit unnest syntax explicit by using UNNEST calls *(PR [#3005](https://github.com/tobymao/sqlglot/pull/3005) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#2996](https://github.com/tobymao/sqlglot/issues/2996) opened by [@wizardxz](https://github.com/wizardxz)*
- [`8943179`](https://github.com/tobymao/sqlglot/commit/8943179dfadba4ed36740322e1e5d3611032b51e) - move limit method to Query, get rid of Subquery.subquery override *(PR [#3013](https://github.com/tobymao/sqlglot/pull/3013) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`9595240`](https://github.com/tobymao/sqlglot/commit/9595240a1c0f0e5ace9f67f31564e5d5edb9a9d2) - make prewhere clickhouse only *(commit by [@tobymao](https://github.com/tobymao))*
## [v21.2.1] - 2024-02-22
### :sparkles: New Features
- [`2a88e40`](https://github.com/tobymao/sqlglot/commit/2a88e40da89fa083bbd8fd0174082fa8e677780a) - **bigquery**: support ELSE and ELSEIF procedural statements *(PR [#3011](https://github.com/tobymao/sqlglot/pull/3011) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#3009](https://github.com/tobymao/sqlglot/issues/3009) opened by [@razvan-am](https://github.com/razvan-am)*
- [`d2e15ed`](https://github.com/tobymao/sqlglot/commit/d2e15ed9b2ab2699f7105f73170b9d780293d432) - improve transpilation of Doris' MONTHS_ADD *(PR [#3012](https://github.com/tobymao/sqlglot/pull/3012) by [@georgesittas](https://github.com/georgesittas))*
### :bug: Bug Fixes
- [`c23ac05`](https://github.com/tobymao/sqlglot/commit/c23ac05379e2aa5cb5681e26e2c0b8137300baa3) - bigquery group by order by rewriting with indices *(commit by [@tobymao](https://github.com/tobymao))*
## [v21.2.0] - 2024-02-22
### :boom: BREAKING CHANGES
- due to [`2940417`](https://github.com/tobymao/sqlglot/commit/2940417116761f821c913bf093759243db33c343) - simplify ADD CONSTRAINT handling *(PR [#2990](https://github.com/tobymao/sqlglot/pull/2990) by [@georgesittas](https://github.com/georgesittas))*:
simplify ADD CONSTRAINT handling (#2990)
### :sparkles: New Features
- [`7c48079`](https://github.com/tobymao/sqlglot/commit/7c4807918de53d18fbfe0295b2644f0ad46003a8) - support parameters in BigQuery / DuckDB *(PR [#2991](https://github.com/tobymao/sqlglot/pull/2991) by [@r1b](https://github.com/r1b))*
- [`b7c2744`](https://github.com/tobymao/sqlglot/commit/b7c2744eba3df631b575e8ab35f29f46419f83ba) - **tests**: update test_executor with tpc-ds *(PR [#2983](https://github.com/tobymao/sqlglot/pull/2983) by [@fool1280](https://github.com/fool1280))*
- [`c433cad`](https://github.com/tobymao/sqlglot/commit/c433cad7df383e97308ceb946d7f1dc171a5d60b) - allow more leniant bigquery wildcard parsing *(PR [#2998](https://github.com/tobymao/sqlglot/pull/2998) by [@tobymao](https://github.com/tobymao))*
- [`8607247`](https://github.com/tobymao/sqlglot/commit/860724732b70b5557221998a45c3c950b39d664a) - support LEFT JOIN UNNEST in duckdb *(PR [#2999](https://github.com/tobymao/sqlglot/pull/2999) by [@r1b](https://github.com/r1b))*
- [`64e38ed`](https://github.com/tobymao/sqlglot/commit/64e38edb32f9a66a9503e75424d0545da3dbe5df) - add support for more Snowflake SHOW commands *(PR [#3002](https://github.com/tobymao/sqlglot/pull/3002) by [@DanCardin](https://github.com/DanCardin))*
### :bug: Bug Fixes
- [`bc18f56`](https://github.com/tobymao/sqlglot/commit/bc18f56a39e0034e2b285efd7a882a417c517a99) - **optimizer**: don't coerce nested arg types in annotate_by_args *(PR [#2997](https://github.com/tobymao/sqlglot/pull/2997) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#2152](https://github.com/TobikoData/sqlmesh/issues/2152) opened by [@plaflamme](https://github.com/plaflamme)*
- [`ccd8cc0`](https://github.com/tobymao/sqlglot/commit/ccd8cc01429d21653198edce079679e17dbb22f6) - doris to_char closes [#3001](https://github.com/tobymao/sqlglot/pull/3001) *(commit by [@tobymao](https://github.com/tobymao))*
### :recycle: Refactors
- [`2940417`](https://github.com/tobymao/sqlglot/commit/2940417116761f821c913bf093759243db33c343) - simplify ADD CONSTRAINT handling *(PR [#2990](https://github.com/tobymao/sqlglot/pull/2990) by [@georgesittas](https://github.com/georgesittas))*
- [`d2711f7`](https://github.com/tobymao/sqlglot/commit/d2711f717aac4a7b624225d31c7fa827f8287476) - clean up duplicative placeholder_sql implementations *(PR [#2993](https://github.com/tobymao/sqlglot/pull/2993) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`53efb58`](https://github.com/tobymao/sqlglot/commit/53efb587a642a171bdb4fb6ad4c33a83c4391908) - cleanup tests *(commit by [@tobymao](https://github.com/tobymao))*
## [v21.1.2] - 2024-02-19
### :sparkles: New Features
- [`b8cbf66`](https://github.com/tobymao/sqlglot/commit/b8cbf66471158371a27d9145b3b553b7a1384c9d) - **bigquery**: parse procedural EXCEPTION WHEN statement into a Command closes [#2981](https://github.com/tobymao/sqlglot/pull/2981) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`906ceee`](https://github.com/tobymao/sqlglot/commit/906ceee0946c547f83177916c3f8d6aeb23023a8) - **duckdb**: implement generation logic for exp.ArrayAny *(PR [#2984](https://github.com/tobymao/sqlglot/pull/2984) by [@georgesittas](https://github.com/georgesittas))*
- [`92455e4`](https://github.com/tobymao/sqlglot/commit/92455e4d4e2c8d5a874a5050d9a38f943479cdca) - **snowflake**: create storage integration *(PR [#2985](https://github.com/tobymao/sqlglot/pull/2985) by [@tekumara](https://github.com/tekumara))*
- [`bedf6e9`](https://github.com/tobymao/sqlglot/commit/bedf6e9dabf9da25e1fff2f3c8ae22fbf7face0b) - improve transpilation support for ArrayAny *(PR [#2986](https://github.com/tobymao/sqlglot/pull/2986) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#2707](https://github.com/tobymao/sqlglot/issues/2707) opened by [@HuashiSCNU0303](https://github.com/HuashiSCNU0303)*
### :bug: Bug Fixes
- [`cc67ab2`](https://github.com/tobymao/sqlglot/commit/cc67ab2513c71a6b9574f8c3cf4c8ba2927d798f) - **tsql**: map StrPosition back to CHARINDEX fixes [#2968](https://github.com/tobymao/sqlglot/pull/2968) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`46f15ce`](https://github.com/tobymao/sqlglot/commit/46f15cef87de3159bc1d422b2620278e9e27ec16) - **postgres**: ensure json extraction can roundtrip unaltered *(PR [#2974](https://github.com/tobymao/sqlglot/pull/2974) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *fixes issue [#2971](https://github.com/tobymao/sqlglot/issues/2971) opened by [@l-vincent-l](https://github.com/l-vincent-l)*
- [`7ee4fe7`](https://github.com/tobymao/sqlglot/commit/7ee4fe73b29234f2837a212b6c872efd7f5c30ea) - expand using with star except *(commit by [@tobymao](https://github.com/tobymao))*
### :recycle: Refactors
- [`5a34f3d`](https://github.com/tobymao/sqlglot/commit/5a34f3d5f652ac209fd122aa25e46d99d8e5cba6) - clean up tech debt in dialect implementations *(PR [#2977](https://github.com/tobymao/sqlglot/pull/2977) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`ae92789`](https://github.com/tobymao/sqlglot/commit/ae92789cdac4c4f0bb3d5f542bd9fe93aee4ea70) - rephrase some sentences in the FAQ section *(PR [#2980](https://github.com/tobymao/sqlglot/pull/2980) by [@georgesittas](https://github.com/georgesittas))*
- [`22ed4d0`](https://github.com/tobymao/sqlglot/commit/22ed4d0a976dbba15962670873422e86874680b0) - cleanup kv defs from brackets *(PR [#2987](https://github.com/tobymao/sqlglot/pull/2987) by [@tobymao](https://github.com/tobymao))*
## [v21.1.1] - 2024-02-14
### :sparkles: New Features
- [`1d0b3d3`](https://github.com/tobymao/sqlglot/commit/1d0b3d3a22ba5a8128505d636a2ff71d0ea03d03) - add support for multi-part interval addition syntax *(PR [#2970](https://github.com/tobymao/sqlglot/pull/2970) by [@georgesittas](https://github.com/georgesittas))*
@ -2634,3 +2792,11 @@ Changelog
[v21.0.2]: https://github.com/tobymao/sqlglot/compare/v21.0.1...v21.0.2
[v21.1.0]: https://github.com/tobymao/sqlglot/compare/v21.0.2...v21.1.0
[v21.1.1]: https://github.com/tobymao/sqlglot/compare/v21.1.0...v21.1.1
[v21.1.2]: https://github.com/tobymao/sqlglot/compare/v21.1.1...v21.1.2
[v21.2.0]: https://github.com/tobymao/sqlglot/compare/v21.1.2...v21.2.0
[v21.2.1]: https://github.com/tobymao/sqlglot/compare/v21.2.0...v21.2.1
[v22.0.0]: https://github.com/tobymao/sqlglot/compare/v21.2.1...v22.0.0
[v22.0.1]: https://github.com/tobymao/sqlglot/compare/v22.0.0...v22.0.1
[v22.0.2]: https://github.com/tobymao/sqlglot/compare/v22.0.1...v22.0.2
[v22.1.0]: https://github.com/tobymao/sqlglot/compare/v22.0.2...v22.1.0
[v22.1.1]: https://github.com/tobymao/sqlglot/compare/v22.1.0...v22.1.1

View file

@ -96,7 +96,7 @@ sqlglot.transpile("SELECT EPOCH_MS(1618088028295)", read="duckdb", write="hive")
```
```sql
'SELECT FROM_UNIXTIME(1618088028295 / 1000)'
'SELECT FROM_UNIXTIME(1618088028295 / POW(10, 3))'
```
SQLGlot can even translate custom time formats:
@ -202,13 +202,13 @@ When the parser detects an error in the syntax, it raises a ParseError:
```python
import sqlglot
sqlglot.transpile("SELECT foo( FROM bar")
sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
```
```
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 13.
select foo( FROM bar
~~~~
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 34.
SELECT foo FROM (SELECT baz FROM t
~
```
Structured syntax errors are accessible for programmatic use:
@ -216,7 +216,7 @@ Structured syntax errors are accessible for programmatic use:
```python
import sqlglot
try:
sqlglot.transpile("SELECT foo( FROM bar")
sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
except sqlglot.errors.ParseError as e:
print(e.errors)
```
@ -225,11 +225,11 @@ except sqlglot.errors.ParseError as e:
[{
'description': 'Expecting )',
'line': 1,
'col': 16,
'start_context': 'SELECT foo( ',
'highlight': 'FROM',
'end_context': ' bar',
'into_expression': None,
'col': 34,
'start_context': 'SELECT foo FROM (SELECT baz FROM ',
'highlight': 't',
'end_context': '',
'into_expression': None
}]
```

File diff suppressed because one or more lines are too long

View file

@ -178,19 +178,19 @@
<p>I tried to parse SQL that should be valid but it failed, why did that happen?</p>
<ul>
<li>You need to specify the dialect to read the SQL properly, by default it is SQLGlot's dialect which is designed to be a superset of all dialects <code>parse_one(sql, dialect="spark")</code>. If you tried specifying the dialect and it still doesn't work, please file an issue.</li>
<li>Most of the time, issues like this occur because the "source" dialect is omitted during parsing. For example, this is how to correctly parse a SQL query written in Spark SQL: <code>parse_one(sql, dialect="spark")</code> (alternatively: <code>read="spark"</code>). If no dialect is specified, <code><a href="#parse_one">parse_one</a></code> will attempt to parse the query according to the "SQLGlot dialect", which is designed to be a superset of all supported dialects. If you tried specifying the dialect and it still doesn't work, please file an issue.</li>
</ul>
<p>I tried to output SQL but it's not in the correct dialect!</p>
<ul>
<li>You need to specify the dialect to write the sql properly, by default it is in SQLGlot's dialect <code>parse_one(sql, dialect="spark").sql(dialect="spark")</code>.</li>
<li>Like parsing, generating SQL also requires the target dialect to be specified, otherwise the SQLGlot dialect will be used by default. For example, to transpile a query from Spark SQL to DuckDB, do <code>parse_one(sql, dialect="spark").sql(dialect="duckdb")</code> (alternatively: <code>transpile(sql, read="spark", write="duckdb")</code>).</li>
</ul>
<p>I tried to parse invalid SQL and it should raise an error but it worked! Why didn't it validate my SQL.</p>
<p>I tried to parse invalid SQL and it worked, even though it should raise an error! Why didn't it validate my SQL?</p>
<ul>
<li>SQLGlot is not a validator and designed to be very forgiving, handling things like trailing commas.</li>
<li>SQLGlot does not aim to be a SQL validator - it is designed to be very forgiving. This makes the codebase more comprehensive and also gives more flexibility to its users, e.g. by allowing them to include trailing commas in their projection lists.</li>
</ul>
<h2 id="examples">Examples</h2>
@ -206,7 +206,7 @@
</div>
<div class="pdoc-code codehilite">
<pre><span></span><code><span class="s1">&#39;SELECT FROM_UNIXTIME(1618088028295 / 1000)&#39;</span>
<pre><span></span><code><span class="s1">&#39;SELECT FROM_UNIXTIME(1618088028295 / POW(10, 3))&#39;</span>
</code></pre>
</div>
@ -319,13 +319,13 @@
<div class="pdoc-code codehilite">
<pre><span></span><code><span class="kn">import</span> <span class="nn">sqlglot</span>
<span class="n"><a href="#transpile">transpile</a></span><span class="p">(</span><span class="s2">&quot;SELECT foo( FROM bar&quot;</span><span class="p">)</span>
<span class="n"><a href="#transpile">transpile</a></span><span class="p">(</span><span class="s2">&quot;SELECT foo FROM (SELECT baz FROM t&quot;</span><span class="p">)</span>
</code></pre>
</div>
<pre><code><a href="sqlglot/errors.html#ParseError">sqlglot.errors.ParseError</a>: Expecting ). Line 1, Col: 13.
select foo( FROM bar
~~~~
<pre><code><a href="sqlglot/errors.html#ParseError">sqlglot.errors.ParseError</a>: Expecting ). Line 1, Col: 34.
SELECT foo FROM (SELECT baz FROM t
~
</code></pre>
<p>Structured syntax errors are accessible for programmatic use:</p>
@ -333,7 +333,7 @@
<div class="pdoc-code codehilite">
<pre><span></span><code><span class="kn">import</span> <span class="nn">sqlglot</span>
<span class="k">try</span><span class="p">:</span>
<span class="n"><a href="#transpile">transpile</a></span><span class="p">(</span><span class="s2">&quot;SELECT foo( FROM bar&quot;</span><span class="p">)</span>
<span class="n"><a href="#transpile">transpile</a></span><span class="p">(</span><span class="s2">&quot;SELECT foo FROM (SELECT baz FROM t&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="n"><a href="sqlglot/errors.html#ParseError">sqlglot.errors.ParseError</a></span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span>
</code></pre>
@ -343,11 +343,11 @@
<pre><span></span><code><span class="p">[{</span>
<span class="s1">&#39;description&#39;</span><span class="p">:</span> <span class="s1">&#39;Expecting )&#39;</span><span class="p">,</span>
<span class="s1">&#39;line&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s1">&#39;col&#39;</span><span class="p">:</span> <span class="mi">16</span><span class="p">,</span>
<span class="s1">&#39;start_context&#39;</span><span class="p">:</span> <span class="s1">&#39;SELECT foo( &#39;</span><span class="p">,</span>
<span class="s1">&#39;highlight&#39;</span><span class="p">:</span> <span class="s1">&#39;FROM&#39;</span><span class="p">,</span>
<span class="s1">&#39;end_context&#39;</span><span class="p">:</span> <span class="s1">&#39; bar&#39;</span><span class="p">,</span>
<span class="s1">&#39;into_expression&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s1">&#39;col&#39;</span><span class="p">:</span> <span class="mi">34</span><span class="p">,</span>
<span class="s1">&#39;start_context&#39;</span><span class="p">:</span> <span class="s1">&#39;SELECT foo FROM (SELECT baz FROM &#39;</span><span class="p">,</span>
<span class="s1">&#39;highlight&#39;</span><span class="p">:</span> <span class="s1">&#39;t&#39;</span><span class="p">,</span>
<span class="s1">&#39;end_context&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
<span class="s1">&#39;into_expression&#39;</span><span class="p">:</span> <span class="kc">None</span>
<span class="p">}]</span>
</code></pre>
</div>
@ -797,81 +797,79 @@ make check # Full test suite &amp; linter checks
</span><span id="L-88"><a href="#L-88"><span class="linenos"> 88</span></a>
</span><span id="L-89"><a href="#L-89"><span class="linenos"> 89</span></a>
</span><span id="L-90"><a href="#L-90"><span class="linenos"> 90</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</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><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a> <span class="o">...</span>
</span><span id="L-91"><a href="#L-91"><span class="linenos"> 91</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-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><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</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><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a> <span class="o">...</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><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</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-103"><a href="#L-103"><span class="linenos">103</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-104"><a href="#L-104"><span class="linenos">104</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-105"><a href="#L-105"><span class="linenos">105</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-106"><a href="#L-106"><span class="linenos">106</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span>
</span><span id="L-107"><a href="#L-107"><span class="linenos">107</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-108"><a href="#L-108"><span class="linenos">108</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-109"><a href="#L-109"><span class="linenos">109</span></a>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</span></a><span class="sd"> Args:</span>
</span><span id="L-111"><a href="#L-111"><span class="linenos">111</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</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-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd"> Returns:</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</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-96"><a href="#L-96"><span class="linenos"> 96</span></a>
</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="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</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-101"><a href="#L-101"><span class="linenos">101</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-102"><a href="#L-102"><span class="linenos">102</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-103"><a href="#L-103"><span class="linenos">103</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</span>
</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-106"><a href="#L-106"><span class="linenos">106</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-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="sd"> Args:</span>
</span><span id="L-109"><a href="#L-109"><span class="linenos">109</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="L-110"><a href="#L-110"><span class="linenos">110</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-111"><a href="#L-111"><span class="linenos">111</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="L-112"><a href="#L-112"><span class="linenos">112</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="L-113"><a href="#L-113"><span class="linenos">113</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="L-114"><a href="#L-114"><span class="linenos">114</span></a>
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a><span class="sd"> Returns:</span>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</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-120"><a href="#L-120"><span class="linenos">120</span></a>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</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-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="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</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-125"><a href="#L-125"><span class="linenos">125</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</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-127"><a href="#L-127"><span class="linenos">127</span></a>
</span><span id="L-128"><a href="#L-128"><span class="linenos">128</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-129"><a href="#L-129"><span class="linenos">129</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-130"><a href="#L-130"><span class="linenos">130</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-131"><a href="#L-131"><span class="linenos">131</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="L-132"><a href="#L-132"><span class="linenos">132</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-133"><a href="#L-133"><span class="linenos">133</span></a> <span class="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-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><span id="L-136"><a href="#L-136"><span class="linenos">136</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="L-137"><a href="#L-137"><span class="linenos">137</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</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-139"><a href="#L-139"><span class="linenos">139</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-140"><a href="#L-140"><span class="linenos">140</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-141"><a href="#L-141"><span class="linenos">141</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-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</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-144"><a href="#L-144"><span class="linenos">144</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-145"><a href="#L-145"><span class="linenos">145</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-146"><a href="#L-146"><span class="linenos">146</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-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="sd"> Args:</span>
</span><span id="L-149"><a href="#L-149"><span class="linenos">149</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="L-150"><a href="#L-150"><span class="linenos">150</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-151"><a href="#L-151"><span class="linenos">151</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-152"><a href="#L-152"><span class="linenos">152</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-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="sd"> Returns:</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="L-159"><a href="#L-159"><span class="linenos">159</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-160"><a href="#L-160"><span class="linenos">160</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-161"><a href="#L-161"><span class="linenos">161</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-162"><a href="#L-162"><span class="linenos">162</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="L-163"><a href="#L-163"><span class="linenos">163</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-164"><a href="#L-164"><span class="linenos">164</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-165"><a href="#L-165"><span class="linenos">165</span></a> <span class="p">]</span>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="L-122"><a href="#L-122"><span class="linenos">122</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-123"><a href="#L-123"><span class="linenos">123</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-124"><a href="#L-124"><span class="linenos">124</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-125"><a href="#L-125"><span class="linenos">125</span></a>
</span><span id="L-126"><a href="#L-126"><span class="linenos">126</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-127"><a href="#L-127"><span class="linenos">127</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-128"><a href="#L-128"><span class="linenos">128</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-129"><a href="#L-129"><span class="linenos">129</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="L-130"><a href="#L-130"><span class="linenos">130</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-131"><a href="#L-131"><span class="linenos">131</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-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><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="L-135"><a href="#L-135"><span class="linenos">135</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="L-136"><a href="#L-136"><span class="linenos">136</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-137"><a href="#L-137"><span class="linenos">137</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-138"><a href="#L-138"><span class="linenos">138</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-139"><a href="#L-139"><span class="linenos">139</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-140"><a href="#L-140"><span class="linenos">140</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</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-142"><a href="#L-142"><span class="linenos">142</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</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-144"><a href="#L-144"><span class="linenos">144</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-145"><a href="#L-145"><span class="linenos">145</span></a>
</span><span id="L-146"><a href="#L-146"><span class="linenos">146</span></a><span class="sd"> Args:</span>
</span><span id="L-147"><a href="#L-147"><span class="linenos">147</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="L-148"><a href="#L-148"><span class="linenos">148</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-149"><a href="#L-149"><span class="linenos">149</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-150"><a href="#L-150"><span class="linenos">150</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-151"><a href="#L-151"><span class="linenos">151</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="L-152"><a href="#L-152"><span class="linenos">152</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="L-153"><a href="#L-153"><span class="linenos">153</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="L-154"><a href="#L-154"><span class="linenos">154</span></a>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="sd"> Returns:</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</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-159"><a href="#L-159"><span class="linenos">159</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-160"><a href="#L-160"><span class="linenos">160</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="L-161"><a href="#L-161"><span class="linenos">161</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-162"><a href="#L-162"><span class="linenos">162</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-163"><a href="#L-163"><span class="linenos">163</span></a> <span class="p">]</span>
</span></pre></div>
@ -977,40 +975,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-101"><a href="#parse_one-101"><span class="linenos">101</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="parse_one-102"><a href="#parse_one-102"><span class="linenos">102</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-103"><a href="#parse_one-103"><span class="linenos">103</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-104"><a href="#parse_one-104"><span class="linenos">104</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-105"><a href="#parse_one-105"><span class="linenos">105</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-106"><a href="#parse_one-106"><span class="linenos">106</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="parse_one-107"><a href="#parse_one-107"><span class="linenos">107</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-108"><a href="#parse_one-108"><span class="linenos">108</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="parse_one-109"><a href="#parse_one-109"><span class="linenos">109</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-110"><a href="#parse_one-110"><span class="linenos">110</span></a>
</span><span id="parse_one-111"><a href="#parse_one-111"><span class="linenos">111</span></a><span class="sd"> Args:</span>
</span><span id="parse_one-112"><a href="#parse_one-112"><span class="linenos">112</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="parse_one-113"><a href="#parse_one-113"><span class="linenos">113</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-114"><a href="#parse_one-114"><span class="linenos">114</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="parse_one-115"><a href="#parse_one-115"><span class="linenos">115</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="parse_one-116"><a href="#parse_one-116"><span class="linenos">116</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="parse_one-117"><a href="#parse_one-117"><span class="linenos">117</span></a>
</span><span id="parse_one-118"><a href="#parse_one-118"><span class="linenos">118</span></a><span class="sd"> Returns:</span>
</span><span id="parse_one-119"><a href="#parse_one-119"><span class="linenos">119</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="parse_one-120"><a href="#parse_one-120"><span class="linenos">120</span></a><span class="sd"> &quot;&quot;&quot;</span>
<div class="pdoc-code codehilite"><pre><span></span><span id="parse_one-99"><a href="#parse_one-99"><span class="linenos"> 99</span></a><span class="k">def</span> <span class="nf">parse_one</span><span class="p">(</span>
</span><span id="parse_one-100"><a href="#parse_one-100"><span class="linenos">100</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-101"><a href="#parse_one-101"><span class="linenos">101</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-102"><a href="#parse_one-102"><span class="linenos">102</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-103"><a href="#parse_one-103"><span class="linenos">103</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-104"><a href="#parse_one-104"><span class="linenos">104</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="parse_one-105"><a href="#parse_one-105"><span class="linenos">105</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-106"><a href="#parse_one-106"><span class="linenos">106</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="parse_one-107"><a href="#parse_one-107"><span class="linenos">107</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-108"><a href="#parse_one-108"><span class="linenos">108</span></a>
</span><span id="parse_one-109"><a href="#parse_one-109"><span class="linenos">109</span></a><span class="sd"> Args:</span>
</span><span id="parse_one-110"><a href="#parse_one-110"><span class="linenos">110</span></a><span class="sd"> sql: the SQL code string to parse.</span>
</span><span id="parse_one-111"><a href="#parse_one-111"><span class="linenos">111</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-112"><a href="#parse_one-112"><span class="linenos">112</span></a><span class="sd"> dialect: the SQL dialect (alias for read)</span>
</span><span id="parse_one-113"><a href="#parse_one-113"><span class="linenos">113</span></a><span class="sd"> into: the SQLGlot Expression to parse into.</span>
</span><span id="parse_one-114"><a href="#parse_one-114"><span class="linenos">114</span></a><span class="sd"> **opts: other `sqlglot.parser.Parser` options.</span>
</span><span id="parse_one-115"><a href="#parse_one-115"><span class="linenos">115</span></a>
</span><span id="parse_one-116"><a href="#parse_one-116"><span class="linenos">116</span></a><span class="sd"> Returns:</span>
</span><span id="parse_one-117"><a href="#parse_one-117"><span class="linenos">117</span></a><span class="sd"> The syntax tree for the first parsed statement.</span>
</span><span id="parse_one-118"><a href="#parse_one-118"><span class="linenos">118</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="parse_one-119"><a href="#parse_one-119"><span class="linenos">119</span></a>
</span><span id="parse_one-120"><a href="#parse_one-120"><span class="linenos">120</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-121"><a href="#parse_one-121"><span class="linenos">121</span></a>
</span><span id="parse_one-122"><a href="#parse_one-122"><span class="linenos">122</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-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="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="parse_one-125"><a href="#parse_one-125"><span class="linenos">125</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-126"><a href="#parse_one-126"><span class="linenos">126</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-127"><a href="#parse_one-127"><span class="linenos">127</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-128"><a href="#parse_one-128"><span class="linenos">128</span></a>
</span><span id="parse_one-129"><a href="#parse_one-129"><span class="linenos">129</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-130"><a href="#parse_one-130"><span class="linenos">130</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-131"><a href="#parse_one-131"><span class="linenos">131</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-132"><a href="#parse_one-132"><span class="linenos">132</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="parse_one-133"><a href="#parse_one-133"><span class="linenos">133</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-134"><a href="#parse_one-134"><span class="linenos">134</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-122"><a href="#parse_one-122"><span class="linenos">122</span></a> <span class="k">if</span> <span class="n">into</span><span class="p">:</span>
</span><span id="parse_one-123"><a href="#parse_one-123"><span class="linenos">123</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-124"><a href="#parse_one-124"><span class="linenos">124</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-125"><a href="#parse_one-125"><span class="linenos">125</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-126"><a href="#parse_one-126"><span class="linenos">126</span></a>
</span><span id="parse_one-127"><a href="#parse_one-127"><span class="linenos">127</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-128"><a href="#parse_one-128"><span class="linenos">128</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-129"><a href="#parse_one-129"><span class="linenos">129</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-130"><a href="#parse_one-130"><span class="linenos">130</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="parse_one-131"><a href="#parse_one-131"><span class="linenos">131</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="parse_one-132"><a href="#parse_one-132"><span class="linenos">132</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>
@ -1046,36 +1044,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-137"><a href="#transpile-137"><span class="linenos">137</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="transpile-138"><a href="#transpile-138"><span class="linenos">138</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="transpile-139"><a href="#transpile-139"><span class="linenos">139</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-140"><a href="#transpile-140"><span class="linenos">140</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-141"><a href="#transpile-141"><span class="linenos">141</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-142"><a href="#transpile-142"><span class="linenos">142</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-143"><a href="#transpile-143"><span class="linenos">143</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="transpile-144"><a href="#transpile-144"><span class="linenos">144</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-145"><a href="#transpile-145"><span class="linenos">145</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="transpile-146"><a href="#transpile-146"><span class="linenos">146</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-147"><a href="#transpile-147"><span class="linenos">147</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-148"><a href="#transpile-148"><span class="linenos">148</span></a>
</span><span id="transpile-149"><a href="#transpile-149"><span class="linenos">149</span></a><span class="sd"> Args:</span>
</span><span id="transpile-150"><a href="#transpile-150"><span class="linenos">150</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="transpile-151"><a href="#transpile-151"><span class="linenos">151</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-152"><a href="#transpile-152"><span class="linenos">152</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-153"><a href="#transpile-153"><span class="linenos">153</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-154"><a href="#transpile-154"><span class="linenos">154</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="transpile-155"><a href="#transpile-155"><span class="linenos">155</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="transpile-156"><a href="#transpile-156"><span class="linenos">156</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="transpile-157"><a href="#transpile-157"><span class="linenos">157</span></a>
</span><span id="transpile-158"><a href="#transpile-158"><span class="linenos">158</span></a><span class="sd"> Returns:</span>
</span><span id="transpile-159"><a href="#transpile-159"><span class="linenos">159</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="transpile-160"><a href="#transpile-160"><span class="linenos">160</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="transpile-161"><a href="#transpile-161"><span class="linenos">161</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-162"><a href="#transpile-162"><span class="linenos">162</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-163"><a href="#transpile-163"><span class="linenos">163</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="transpile-164"><a href="#transpile-164"><span class="linenos">164</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-165"><a href="#transpile-165"><span class="linenos">165</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-166"><a href="#transpile-166"><span class="linenos">166</span></a> <span class="p">]</span>
<div class="pdoc-code codehilite"><pre><span></span><span id="transpile-135"><a href="#transpile-135"><span class="linenos">135</span></a><span class="k">def</span> <span class="nf">transpile</span><span class="p">(</span>
</span><span id="transpile-136"><a href="#transpile-136"><span class="linenos">136</span></a> <span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
</span><span id="transpile-137"><a href="#transpile-137"><span class="linenos">137</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-138"><a href="#transpile-138"><span class="linenos">138</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-139"><a href="#transpile-139"><span class="linenos">139</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-140"><a href="#transpile-140"><span class="linenos">140</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-141"><a href="#transpile-141"><span class="linenos">141</span></a> <span class="o">**</span><span class="n">opts</span><span class="p">,</span>
</span><span id="transpile-142"><a href="#transpile-142"><span class="linenos">142</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-143"><a href="#transpile-143"><span class="linenos">143</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="transpile-144"><a href="#transpile-144"><span class="linenos">144</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-145"><a href="#transpile-145"><span class="linenos">145</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-146"><a href="#transpile-146"><span class="linenos">146</span></a>
</span><span id="transpile-147"><a href="#transpile-147"><span class="linenos">147</span></a><span class="sd"> Args:</span>
</span><span id="transpile-148"><a href="#transpile-148"><span class="linenos">148</span></a><span class="sd"> sql: the SQL code string to transpile.</span>
</span><span id="transpile-149"><a href="#transpile-149"><span class="linenos">149</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-150"><a href="#transpile-150"><span class="linenos">150</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-151"><a href="#transpile-151"><span class="linenos">151</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-152"><a href="#transpile-152"><span class="linenos">152</span></a><span class="sd"> the source and the target dialect.</span>
</span><span id="transpile-153"><a href="#transpile-153"><span class="linenos">153</span></a><span class="sd"> error_level: the desired error level of the parser.</span>
</span><span id="transpile-154"><a href="#transpile-154"><span class="linenos">154</span></a><span class="sd"> **opts: other `sqlglot.generator.Generator` options.</span>
</span><span id="transpile-155"><a href="#transpile-155"><span class="linenos">155</span></a>
</span><span id="transpile-156"><a href="#transpile-156"><span class="linenos">156</span></a><span class="sd"> Returns:</span>
</span><span id="transpile-157"><a href="#transpile-157"><span class="linenos">157</span></a><span class="sd"> The list of transpiled SQL statements.</span>
</span><span id="transpile-158"><a href="#transpile-158"><span class="linenos">158</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="transpile-159"><a href="#transpile-159"><span class="linenos">159</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-160"><a href="#transpile-160"><span class="linenos">160</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-161"><a href="#transpile-161"><span class="linenos">161</span></a> <span class="k">return</span> <span class="p">[</span>
</span><span id="transpile-162"><a href="#transpile-162"><span class="linenos">162</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-163"><a href="#transpile-163"><span class="linenos">163</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-164"><a href="#transpile-164"><span class="linenos">164</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;21.1.1&#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">21</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</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;22.1.1&#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">22</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</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;21.1.1&#39;</span>
<span class="default_value">&#39;22.1.1&#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">(21, 1, 1)</span>
<span class="default_value">(22, 1, 1)</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

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

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

@ -187,7 +187,7 @@
</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a> <span class="k">def</span> <span class="nf">sort</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a> <span class="k">def</span> <span class="nf">sort_key</span><span class="p">(</span><span class="n">row</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">:</span>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">set_row</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a> <span class="k">return</span> <span class="nb">tuple</span><span class="p">((</span><span class="n">t</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">))</span>
</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a>
</span><span id="L-83"><a href="#L-83"><span class="linenos"> 83</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">rows</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">sort_key</span><span class="p">)</span>
</span><span id="L-84"><a href="#L-84"><span class="linenos"> 84</span></a>
@ -293,7 +293,7 @@
</span><span id="Context-79"><a href="#Context-79"><span class="linenos"> 79</span></a> <span class="k">def</span> <span class="nf">sort</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="Context-80"><a href="#Context-80"><span class="linenos"> 80</span></a> <span class="k">def</span> <span class="nf">sort_key</span><span class="p">(</span><span class="n">row</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">:</span>
</span><span id="Context-81"><a href="#Context-81"><span class="linenos"> 81</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">set_row</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span><span id="Context-82"><a href="#Context-82"><span class="linenos"> 82</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
</span><span id="Context-82"><a href="#Context-82"><span class="linenos"> 82</span></a> <span class="k">return</span> <span class="nb">tuple</span><span class="p">((</span><span class="n">t</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">))</span>
</span><span id="Context-83"><a href="#Context-83"><span class="linenos"> 83</span></a>
</span><span id="Context-84"><a href="#Context-84"><span class="linenos"> 84</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">rows</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">sort_key</span><span class="p">)</span>
</span><span id="Context-85"><a href="#Context-85"><span class="linenos"> 85</span></a>
@ -561,7 +561,7 @@ evaluation of aggregation functions.</p>
<div class="pdoc-code codehilite"><pre><span></span><span id="Context.sort-79"><a href="#Context.sort-79"><span class="linenos">79</span></a> <span class="k">def</span> <span class="nf">sort</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span><span id="Context.sort-80"><a href="#Context.sort-80"><span class="linenos">80</span></a> <span class="k">def</span> <span class="nf">sort_key</span><span class="p">(</span><span class="n">row</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Tuple</span><span class="p">:</span>
</span><span id="Context.sort-81"><a href="#Context.sort-81"><span class="linenos">81</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">set_row</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span><span id="Context.sort-82"><a href="#Context.sort-82"><span class="linenos">82</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
</span><span id="Context.sort-82"><a href="#Context.sort-82"><span class="linenos">82</span></a> <span class="k">return</span> <span class="nb">tuple</span><span class="p">((</span><span class="n">t</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">eval_tuple</span><span class="p">(</span><span class="n">key</span><span class="p">))</span>
</span><span id="Context.sort-83"><a href="#Context.sort-83"><span class="linenos">83</span></a>
</span><span id="Context.sort-84"><a href="#Context.sort-84"><span class="linenos">84</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">rows</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">sort_key</span><span class="p">)</span>
</span></pre></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 it is too large Load diff

View file

@ -394,7 +394,6 @@
<dd id="JSONPathTokenizer.dialect" class="variable"><a href="tokens.html#Tokenizer.dialect">dialect</a></dd>
<dd id="JSONPathTokenizer.reset" class="function"><a href="tokens.html#Tokenizer.reset">reset</a></dd>
<dd id="JSONPathTokenizer.tokenize" class="function"><a href="tokens.html#Tokenizer.tokenize">tokenize</a></dd>
<dd id="JSONPathTokenizer.peek" class="function"><a href="tokens.html#Tokenizer.peek">peek</a></dd>
<dd id="JSONPathTokenizer.tokenize_rs" class="function"><a href="tokens.html#Tokenizer.tokenize_rs">tokenize_rs</a></dd>
<dd id="JSONPathTokenizer.size" class="variable"><a href="tokens.html#Tokenizer.size">size</a></dd>
<dd id="JSONPathTokenizer.sql" class="variable"><a href="tokens.html#Tokenizer.sql">sql</a></dd>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

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

View file

@ -146,7 +146,7 @@
</span><span id="L-76"><a href="#L-76"><span class="linenos"> 76</span></a>
</span><span id="L-77"><a href="#L-77"><span class="linenos"> 77</span></a><span class="sd"> Args:</span>
</span><span id="L-78"><a href="#L-78"><span class="linenos"> 78</span></a><span class="sd"> expression: The expression to check if it&#39;s normalized.</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd"> dnf: Whether or not to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="L-79"><a href="#L-79"><span class="linenos"> 79</span></a><span class="sd"> dnf: Whether to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="L-80"><a href="#L-80"><span class="linenos"> 80</span></a><span class="sd"> Default: False, i.e. we check if it&#39;s in Conjunctive Normal Form (CNF).</span>
</span><span id="L-81"><a href="#L-81"><span class="linenos"> 81</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-82"><a href="#L-82"><span class="linenos"> 82</span></a> <span class="n">ancestor</span><span class="p">,</span> <span class="n">root</span> <span class="o">=</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">And</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Or</span><span class="p">)</span> <span class="k">if</span> <span class="n">dnf</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Or</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">And</span><span class="p">)</span>
@ -169,7 +169,7 @@
</span><span id="L-99"><a href="#L-99"><span class="linenos"> 99</span></a>
</span><span id="L-100"><a href="#L-100"><span class="linenos">100</span></a><span class="sd"> Args:</span>
</span><span id="L-101"><a href="#L-101"><span class="linenos">101</span></a><span class="sd"> expression: The expression to compute the normalization distance for.</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="sd"> dnf: Whether or not to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="L-102"><a href="#L-102"><span class="linenos">102</span></a><span class="sd"> dnf: Whether to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="L-103"><a href="#L-103"><span class="linenos">103</span></a><span class="sd"> Default: False, i.e. we check if it&#39;s in Conjunctive Normal Form (CNF).</span>
</span><span id="L-104"><a href="#L-104"><span class="linenos">104</span></a>
</span><span id="L-105"><a href="#L-105"><span class="linenos">105</span></a><span class="sd"> Returns:</span>
@ -387,7 +387,7 @@
</span><span id="normalized-77"><a href="#normalized-77"><span class="linenos">77</span></a>
</span><span id="normalized-78"><a href="#normalized-78"><span class="linenos">78</span></a><span class="sd"> Args:</span>
</span><span id="normalized-79"><a href="#normalized-79"><span class="linenos">79</span></a><span class="sd"> expression: The expression to check if it&#39;s normalized.</span>
</span><span id="normalized-80"><a href="#normalized-80"><span class="linenos">80</span></a><span class="sd"> dnf: Whether or not to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="normalized-80"><a href="#normalized-80"><span class="linenos">80</span></a><span class="sd"> dnf: Whether to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="normalized-81"><a href="#normalized-81"><span class="linenos">81</span></a><span class="sd"> Default: False, i.e. we check if it&#39;s in Conjunctive Normal Form (CNF).</span>
</span><span id="normalized-82"><a href="#normalized-82"><span class="linenos">82</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="normalized-83"><a href="#normalized-83"><span class="linenos">83</span></a> <span class="n">ancestor</span><span class="p">,</span> <span class="n">root</span> <span class="o">=</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">And</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Or</span><span class="p">)</span> <span class="k">if</span> <span class="n">dnf</span> <span class="k">else</span> <span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">Or</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">And</span><span class="p">)</span>
@ -418,7 +418,7 @@
<ul>
<li><strong>expression:</strong> The expression to check if it's normalized.</li>
<li><strong>dnf:</strong> Whether or not to check if the expression is in Disjunctive Normal Form (DNF).
<li><strong>dnf:</strong> Whether to check if the expression is in Disjunctive Normal Form (DNF).
Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
</ul>
</div>
@ -450,7 +450,7 @@ Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
</span><span id="normalization_distance-100"><a href="#normalization_distance-100"><span class="linenos">100</span></a>
</span><span id="normalization_distance-101"><a href="#normalization_distance-101"><span class="linenos">101</span></a><span class="sd"> Args:</span>
</span><span id="normalization_distance-102"><a href="#normalization_distance-102"><span class="linenos">102</span></a><span class="sd"> expression: The expression to compute the normalization distance for.</span>
</span><span id="normalization_distance-103"><a href="#normalization_distance-103"><span class="linenos">103</span></a><span class="sd"> dnf: Whether or not to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="normalization_distance-103"><a href="#normalization_distance-103"><span class="linenos">103</span></a><span class="sd"> dnf: Whether to check if the expression is in Disjunctive Normal Form (DNF).</span>
</span><span id="normalization_distance-104"><a href="#normalization_distance-104"><span class="linenos">104</span></a><span class="sd"> Default: False, i.e. we check if it&#39;s in Conjunctive Normal Form (CNF).</span>
</span><span id="normalization_distance-105"><a href="#normalization_distance-105"><span class="linenos">105</span></a>
</span><span id="normalization_distance-106"><a href="#normalization_distance-106"><span class="linenos">106</span></a><span class="sd"> Returns:</span>
@ -482,7 +482,7 @@ Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
<ul>
<li><strong>expression:</strong> The expression to compute the normalization distance for.</li>
<li><strong>dnf:</strong> Whether or not to check if the expression is in Disjunctive Normal Form (DNF).
<li><strong>dnf:</strong> Whether to check if the expression is in Disjunctive Normal Form (DNF).
Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
</ul>

View file

@ -68,58 +68,56 @@
</span><span id="L-10"><a href="#L-10"><span class="linenos">10</span></a>
</span><span id="L-11"><a href="#L-11"><span class="linenos">11</span></a>
</span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="n">E</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">E</span><span class="p">:</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a> <span class="o">...</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="n">E</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">E</span><span class="p">:</span> <span class="o">...</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><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a>
</span><span id="L-17"><a href="#L-17"><span class="linenos">17</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-18"><a href="#L-18"><span class="linenos">18</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="nb">str</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">exp</span><span class="o">.</span><span class="n">Identifier</span><span class="p">:</span>
</span><span id="L-19"><a href="#L-19"><span class="linenos">19</span></a> <span class="o">...</span>
</span><span id="L-20"><a href="#L-20"><span class="linenos">20</span></a>
</span><span id="L-21"><a href="#L-21"><span class="linenos">21</span></a>
</span><span id="L-22"><a href="#L-22"><span class="linenos">22</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span><span id="L-23"><a href="#L-23"><span class="linenos">23</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-24"><a href="#L-24"><span class="linenos">24</span></a><span class="sd"> Normalize all unquoted identifiers to either lower or upper case, depending</span>
</span><span id="L-25"><a href="#L-25"><span class="linenos">25</span></a><span class="sd"> on the dialect. This essentially makes those identifiers case-insensitive.</span>
</span><span id="L-26"><a href="#L-26"><span class="linenos">26</span></a>
</span><span id="L-27"><a href="#L-27"><span class="linenos">27</span></a><span class="sd"> It&#39;s possible to make this a no-op by adding a special comment next to the</span>
</span><span id="L-28"><a href="#L-28"><span class="linenos">28</span></a><span class="sd"> identifier of interest:</span>
</span><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a><span class="nd">@t</span><span class="o">.</span><span class="n">overload</span>
</span><span id="L-17"><a href="#L-17"><span class="linenos">17</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="nb">str</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">exp</span><span class="o">.</span><span class="n">Identifier</span><span class="p">:</span> <span class="o">...</span>
</span><span id="L-18"><a href="#L-18"><span class="linenos">18</span></a>
</span><span id="L-19"><a href="#L-19"><span class="linenos">19</span></a>
</span><span id="L-20"><a href="#L-20"><span class="linenos">20</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span><span id="L-21"><a href="#L-21"><span class="linenos">21</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-22"><a href="#L-22"><span class="linenos">22</span></a><span class="sd"> Normalize all unquoted identifiers to either lower or upper case, depending</span>
</span><span id="L-23"><a href="#L-23"><span class="linenos">23</span></a><span class="sd"> on the dialect. This essentially makes those identifiers case-insensitive.</span>
</span><span id="L-24"><a href="#L-24"><span class="linenos">24</span></a>
</span><span id="L-25"><a href="#L-25"><span class="linenos">25</span></a><span class="sd"> It&#39;s possible to make this a no-op by adding a special comment next to the</span>
</span><span id="L-26"><a href="#L-26"><span class="linenos">26</span></a><span class="sd"> identifier of interest:</span>
</span><span id="L-27"><a href="#L-27"><span class="linenos">27</span></a>
</span><span id="L-28"><a href="#L-28"><span class="linenos">28</span></a><span class="sd"> SELECT a /* sqlglot.meta case_sensitive */ FROM table</span>
</span><span id="L-29"><a href="#L-29"><span class="linenos">29</span></a>
</span><span id="L-30"><a href="#L-30"><span class="linenos">30</span></a><span class="sd"> SELECT a /* sqlglot.meta case_sensitive */ FROM table</span>
</span><span id="L-30"><a href="#L-30"><span class="linenos">30</span></a><span class="sd"> In this example, the identifier `a` will not be normalized.</span>
</span><span id="L-31"><a href="#L-31"><span class="linenos">31</span></a>
</span><span id="L-32"><a href="#L-32"><span class="linenos">32</span></a><span class="sd"> In this example, the identifier `a` will not be normalized.</span>
</span><span id="L-33"><a href="#L-33"><span class="linenos">33</span></a>
</span><span id="L-34"><a href="#L-34"><span class="linenos">34</span></a><span class="sd"> Note:</span>
</span><span id="L-35"><a href="#L-35"><span class="linenos">35</span></a><span class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</span>
</span><span id="L-36"><a href="#L-36"><span class="linenos">36</span></a><span class="sd"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span>
</span><span id="L-37"><a href="#L-37"><span class="linenos">37</span></a>
</span><span id="L-38"><a href="#L-38"><span class="linenos">38</span></a><span class="sd"> Example:</span>
</span><span id="L-39"><a href="#L-39"><span class="linenos">39</span></a><span class="sd"> &gt;&gt;&gt; import sqlglot</span>
</span><span id="L-40"><a href="#L-40"><span class="linenos">40</span></a><span class="sd"> &gt;&gt;&gt; expression = sqlglot.parse_one(&#39;SELECT Bar.A AS A FROM &quot;Foo&quot;.Bar&#39;)</span>
</span><span id="L-41"><a href="#L-41"><span class="linenos">41</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(expression).sql()</span>
</span><span id="L-42"><a href="#L-42"><span class="linenos">42</span></a><span class="sd"> &#39;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</span>
</span><span id="L-43"><a href="#L-43"><span class="linenos">43</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(&quot;foo&quot;, dialect=&quot;snowflake&quot;).sql(dialect=&quot;snowflake&quot;)</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos">44</span></a><span class="sd"> &#39;FOO&#39;</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos">45</span></a>
</span><span id="L-46"><a href="#L-46"><span class="linenos">46</span></a><span class="sd"> Args:</span>
</span><span id="L-47"><a href="#L-47"><span class="linenos">47</span></a><span class="sd"> expression: The expression to transform.</span>
</span><span id="L-48"><a href="#L-48"><span class="linenos">48</span></a><span class="sd"> dialect: The dialect to use in order to decide how to normalize identifiers.</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos">49</span></a>
</span><span id="L-50"><a href="#L-50"><span class="linenos">50</span></a><span class="sd"> Returns:</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos">51</span></a><span class="sd"> The transformed expression.</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos">52</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-53"><a href="#L-53"><span class="linenos">53</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">dialect</span><span class="p">)</span>
</span><span id="L-54"><a href="#L-54"><span class="linenos">54</span></a>
</span><span id="L-55"><a href="#L-55"><span class="linenos">55</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos">56</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">parse_identifier</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="n">dialect</span><span class="p">)</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos">57</span></a>
</span><span id="L-58"><a href="#L-58"><span class="linenos">58</span></a> <span class="k">def</span> <span class="nf">_normalize</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">E</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos">59</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">meta</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;case_sensitive&quot;</span><span class="p">):</span>
</span><span id="L-60"><a href="#L-60"><span class="linenos">60</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">replace_children</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">_normalize</span><span class="p">)</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos">61</span></a> <span class="n">node</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">normalize_identifier</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-62"><a href="#L-62"><span class="linenos">62</span></a> <span class="k">return</span> <span class="n">node</span>
</span><span id="L-63"><a href="#L-63"><span class="linenos">63</span></a>
</span><span id="L-64"><a href="#L-64"><span class="linenos">64</span></a> <span class="k">return</span> <span class="n">_normalize</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-32"><a href="#L-32"><span class="linenos">32</span></a><span class="sd"> Note:</span>
</span><span id="L-33"><a href="#L-33"><span class="linenos">33</span></a><span class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</span>
</span><span id="L-34"><a href="#L-34"><span class="linenos">34</span></a><span class="sd"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span>
</span><span id="L-35"><a href="#L-35"><span class="linenos">35</span></a>
</span><span id="L-36"><a href="#L-36"><span class="linenos">36</span></a><span class="sd"> Example:</span>
</span><span id="L-37"><a href="#L-37"><span class="linenos">37</span></a><span class="sd"> &gt;&gt;&gt; import sqlglot</span>
</span><span id="L-38"><a href="#L-38"><span class="linenos">38</span></a><span class="sd"> &gt;&gt;&gt; expression = sqlglot.parse_one(&#39;SELECT Bar.A AS A FROM &quot;Foo&quot;.Bar&#39;)</span>
</span><span id="L-39"><a href="#L-39"><span class="linenos">39</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(expression).sql()</span>
</span><span id="L-40"><a href="#L-40"><span class="linenos">40</span></a><span class="sd"> &#39;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</span>
</span><span id="L-41"><a href="#L-41"><span class="linenos">41</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(&quot;foo&quot;, dialect=&quot;snowflake&quot;).sql(dialect=&quot;snowflake&quot;)</span>
</span><span id="L-42"><a href="#L-42"><span class="linenos">42</span></a><span class="sd"> &#39;FOO&#39;</span>
</span><span id="L-43"><a href="#L-43"><span class="linenos">43</span></a>
</span><span id="L-44"><a href="#L-44"><span class="linenos">44</span></a><span class="sd"> Args:</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos">45</span></a><span class="sd"> expression: The expression to transform.</span>
</span><span id="L-46"><a href="#L-46"><span class="linenos">46</span></a><span class="sd"> dialect: The dialect to use in order to decide how to normalize identifiers.</span>
</span><span id="L-47"><a href="#L-47"><span class="linenos">47</span></a>
</span><span id="L-48"><a href="#L-48"><span class="linenos">48</span></a><span class="sd"> Returns:</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos">49</span></a><span class="sd"> The transformed expression.</span>
</span><span id="L-50"><a href="#L-50"><span class="linenos">50</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos">51</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">dialect</span><span class="p">)</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos">52</span></a>
</span><span id="L-53"><a href="#L-53"><span class="linenos">53</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="L-54"><a href="#L-54"><span class="linenos">54</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">parse_identifier</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="n">dialect</span><span class="p">)</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="k">def</span> <span class="nf">_normalize</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">E</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos">57</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">meta</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;case_sensitive&quot;</span><span class="p">):</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos">58</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">replace_children</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">_normalize</span><span class="p">)</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos">59</span></a> <span class="n">node</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">normalize_identifier</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-60"><a href="#L-60"><span class="linenos">60</span></a> <span class="k">return</span> <span class="n">node</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos">61</span></a>
</span><span id="L-62"><a href="#L-62"><span class="linenos">62</span></a> <span class="k">return</span> <span class="n">_normalize</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span></pre></div>
@ -135,49 +133,49 @@
</div>
<a class="headerlink" href="#normalize_identifiers"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="normalize_identifiers-23"><a href="#normalize_identifiers-23"><span class="linenos">23</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span><span id="normalize_identifiers-24"><a href="#normalize_identifiers-24"><span class="linenos">24</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="normalize_identifiers-25"><a href="#normalize_identifiers-25"><span class="linenos">25</span></a><span class="sd"> Normalize all unquoted identifiers to either lower or upper case, depending</span>
</span><span id="normalize_identifiers-26"><a href="#normalize_identifiers-26"><span class="linenos">26</span></a><span class="sd"> on the dialect. This essentially makes those identifiers case-insensitive.</span>
</span><span id="normalize_identifiers-27"><a href="#normalize_identifiers-27"><span class="linenos">27</span></a>
</span><span id="normalize_identifiers-28"><a href="#normalize_identifiers-28"><span class="linenos">28</span></a><span class="sd"> It&#39;s possible to make this a no-op by adding a special comment next to the</span>
</span><span id="normalize_identifiers-29"><a href="#normalize_identifiers-29"><span class="linenos">29</span></a><span class="sd"> identifier of interest:</span>
<div class="pdoc-code codehilite"><pre><span></span><span id="normalize_identifiers-21"><a href="#normalize_identifiers-21"><span class="linenos">21</span></a><span class="k">def</span> <span class="nf">normalize_identifiers</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span><span id="normalize_identifiers-22"><a href="#normalize_identifiers-22"><span class="linenos">22</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="normalize_identifiers-23"><a href="#normalize_identifiers-23"><span class="linenos">23</span></a><span class="sd"> Normalize all unquoted identifiers to either lower or upper case, depending</span>
</span><span id="normalize_identifiers-24"><a href="#normalize_identifiers-24"><span class="linenos">24</span></a><span class="sd"> on the dialect. This essentially makes those identifiers case-insensitive.</span>
</span><span id="normalize_identifiers-25"><a href="#normalize_identifiers-25"><span class="linenos">25</span></a>
</span><span id="normalize_identifiers-26"><a href="#normalize_identifiers-26"><span class="linenos">26</span></a><span class="sd"> It&#39;s possible to make this a no-op by adding a special comment next to the</span>
</span><span id="normalize_identifiers-27"><a href="#normalize_identifiers-27"><span class="linenos">27</span></a><span class="sd"> identifier of interest:</span>
</span><span id="normalize_identifiers-28"><a href="#normalize_identifiers-28"><span class="linenos">28</span></a>
</span><span id="normalize_identifiers-29"><a href="#normalize_identifiers-29"><span class="linenos">29</span></a><span class="sd"> SELECT a /* sqlglot.meta case_sensitive */ FROM table</span>
</span><span id="normalize_identifiers-30"><a href="#normalize_identifiers-30"><span class="linenos">30</span></a>
</span><span id="normalize_identifiers-31"><a href="#normalize_identifiers-31"><span class="linenos">31</span></a><span class="sd"> SELECT a /* sqlglot.meta case_sensitive */ FROM table</span>
</span><span id="normalize_identifiers-31"><a href="#normalize_identifiers-31"><span class="linenos">31</span></a><span class="sd"> In this example, the identifier `a` will not be normalized.</span>
</span><span id="normalize_identifiers-32"><a href="#normalize_identifiers-32"><span class="linenos">32</span></a>
</span><span id="normalize_identifiers-33"><a href="#normalize_identifiers-33"><span class="linenos">33</span></a><span class="sd"> In this example, the identifier `a` will not be normalized.</span>
</span><span id="normalize_identifiers-34"><a href="#normalize_identifiers-34"><span class="linenos">34</span></a>
</span><span id="normalize_identifiers-35"><a href="#normalize_identifiers-35"><span class="linenos">35</span></a><span class="sd"> Note:</span>
</span><span id="normalize_identifiers-36"><a href="#normalize_identifiers-36"><span class="linenos">36</span></a><span class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</span>
</span><span id="normalize_identifiers-37"><a href="#normalize_identifiers-37"><span class="linenos">37</span></a><span class="sd"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span>
</span><span id="normalize_identifiers-38"><a href="#normalize_identifiers-38"><span class="linenos">38</span></a>
</span><span id="normalize_identifiers-39"><a href="#normalize_identifiers-39"><span class="linenos">39</span></a><span class="sd"> Example:</span>
</span><span id="normalize_identifiers-40"><a href="#normalize_identifiers-40"><span class="linenos">40</span></a><span class="sd"> &gt;&gt;&gt; import sqlglot</span>
</span><span id="normalize_identifiers-41"><a href="#normalize_identifiers-41"><span class="linenos">41</span></a><span class="sd"> &gt;&gt;&gt; expression = sqlglot.parse_one(&#39;SELECT Bar.A AS A FROM &quot;Foo&quot;.Bar&#39;)</span>
</span><span id="normalize_identifiers-42"><a href="#normalize_identifiers-42"><span class="linenos">42</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(expression).sql()</span>
</span><span id="normalize_identifiers-43"><a href="#normalize_identifiers-43"><span class="linenos">43</span></a><span class="sd"> &#39;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</span>
</span><span id="normalize_identifiers-44"><a href="#normalize_identifiers-44"><span class="linenos">44</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(&quot;foo&quot;, dialect=&quot;snowflake&quot;).sql(dialect=&quot;snowflake&quot;)</span>
</span><span id="normalize_identifiers-45"><a href="#normalize_identifiers-45"><span class="linenos">45</span></a><span class="sd"> &#39;FOO&#39;</span>
</span><span id="normalize_identifiers-46"><a href="#normalize_identifiers-46"><span class="linenos">46</span></a>
</span><span id="normalize_identifiers-47"><a href="#normalize_identifiers-47"><span class="linenos">47</span></a><span class="sd"> Args:</span>
</span><span id="normalize_identifiers-48"><a href="#normalize_identifiers-48"><span class="linenos">48</span></a><span class="sd"> expression: The expression to transform.</span>
</span><span id="normalize_identifiers-49"><a href="#normalize_identifiers-49"><span class="linenos">49</span></a><span class="sd"> dialect: The dialect to use in order to decide how to normalize identifiers.</span>
</span><span id="normalize_identifiers-50"><a href="#normalize_identifiers-50"><span class="linenos">50</span></a>
</span><span id="normalize_identifiers-51"><a href="#normalize_identifiers-51"><span class="linenos">51</span></a><span class="sd"> Returns:</span>
</span><span id="normalize_identifiers-52"><a href="#normalize_identifiers-52"><span class="linenos">52</span></a><span class="sd"> The transformed expression.</span>
</span><span id="normalize_identifiers-53"><a href="#normalize_identifiers-53"><span class="linenos">53</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="normalize_identifiers-54"><a href="#normalize_identifiers-54"><span class="linenos">54</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">dialect</span><span class="p">)</span>
</span><span id="normalize_identifiers-55"><a href="#normalize_identifiers-55"><span class="linenos">55</span></a>
</span><span id="normalize_identifiers-56"><a href="#normalize_identifiers-56"><span class="linenos">56</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="normalize_identifiers-57"><a href="#normalize_identifiers-57"><span class="linenos">57</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">parse_identifier</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="n">dialect</span><span class="p">)</span>
</span><span id="normalize_identifiers-58"><a href="#normalize_identifiers-58"><span class="linenos">58</span></a>
</span><span id="normalize_identifiers-59"><a href="#normalize_identifiers-59"><span class="linenos">59</span></a> <span class="k">def</span> <span class="nf">_normalize</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">E</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span>
</span><span id="normalize_identifiers-60"><a href="#normalize_identifiers-60"><span class="linenos">60</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">meta</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;case_sensitive&quot;</span><span class="p">):</span>
</span><span id="normalize_identifiers-61"><a href="#normalize_identifiers-61"><span class="linenos">61</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">replace_children</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">_normalize</span><span class="p">)</span>
</span><span id="normalize_identifiers-62"><a href="#normalize_identifiers-62"><span class="linenos">62</span></a> <span class="n">node</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">normalize_identifier</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="normalize_identifiers-63"><a href="#normalize_identifiers-63"><span class="linenos">63</span></a> <span class="k">return</span> <span class="n">node</span>
</span><span id="normalize_identifiers-64"><a href="#normalize_identifiers-64"><span class="linenos">64</span></a>
</span><span id="normalize_identifiers-65"><a href="#normalize_identifiers-65"><span class="linenos">65</span></a> <span class="k">return</span> <span class="n">_normalize</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="normalize_identifiers-33"><a href="#normalize_identifiers-33"><span class="linenos">33</span></a><span class="sd"> Note:</span>
</span><span id="normalize_identifiers-34"><a href="#normalize_identifiers-34"><span class="linenos">34</span></a><span class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</span>
</span><span id="normalize_identifiers-35"><a href="#normalize_identifiers-35"><span class="linenos">35</span></a><span class="sd"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span>
</span><span id="normalize_identifiers-36"><a href="#normalize_identifiers-36"><span class="linenos">36</span></a>
</span><span id="normalize_identifiers-37"><a href="#normalize_identifiers-37"><span class="linenos">37</span></a><span class="sd"> Example:</span>
</span><span id="normalize_identifiers-38"><a href="#normalize_identifiers-38"><span class="linenos">38</span></a><span class="sd"> &gt;&gt;&gt; import sqlglot</span>
</span><span id="normalize_identifiers-39"><a href="#normalize_identifiers-39"><span class="linenos">39</span></a><span class="sd"> &gt;&gt;&gt; expression = sqlglot.parse_one(&#39;SELECT Bar.A AS A FROM &quot;Foo&quot;.Bar&#39;)</span>
</span><span id="normalize_identifiers-40"><a href="#normalize_identifiers-40"><span class="linenos">40</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(expression).sql()</span>
</span><span id="normalize_identifiers-41"><a href="#normalize_identifiers-41"><span class="linenos">41</span></a><span class="sd"> &#39;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</span>
</span><span id="normalize_identifiers-42"><a href="#normalize_identifiers-42"><span class="linenos">42</span></a><span class="sd"> &gt;&gt;&gt; normalize_identifiers(&quot;foo&quot;, dialect=&quot;snowflake&quot;).sql(dialect=&quot;snowflake&quot;)</span>
</span><span id="normalize_identifiers-43"><a href="#normalize_identifiers-43"><span class="linenos">43</span></a><span class="sd"> &#39;FOO&#39;</span>
</span><span id="normalize_identifiers-44"><a href="#normalize_identifiers-44"><span class="linenos">44</span></a>
</span><span id="normalize_identifiers-45"><a href="#normalize_identifiers-45"><span class="linenos">45</span></a><span class="sd"> Args:</span>
</span><span id="normalize_identifiers-46"><a href="#normalize_identifiers-46"><span class="linenos">46</span></a><span class="sd"> expression: The expression to transform.</span>
</span><span id="normalize_identifiers-47"><a href="#normalize_identifiers-47"><span class="linenos">47</span></a><span class="sd"> dialect: The dialect to use in order to decide how to normalize identifiers.</span>
</span><span id="normalize_identifiers-48"><a href="#normalize_identifiers-48"><span class="linenos">48</span></a>
</span><span id="normalize_identifiers-49"><a href="#normalize_identifiers-49"><span class="linenos">49</span></a><span class="sd"> Returns:</span>
</span><span id="normalize_identifiers-50"><a href="#normalize_identifiers-50"><span class="linenos">50</span></a><span class="sd"> The transformed expression.</span>
</span><span id="normalize_identifiers-51"><a href="#normalize_identifiers-51"><span class="linenos">51</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="normalize_identifiers-52"><a href="#normalize_identifiers-52"><span class="linenos">52</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">dialect</span><span class="p">)</span>
</span><span id="normalize_identifiers-53"><a href="#normalize_identifiers-53"><span class="linenos">53</span></a>
</span><span id="normalize_identifiers-54"><a href="#normalize_identifiers-54"><span class="linenos">54</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="normalize_identifiers-55"><a href="#normalize_identifiers-55"><span class="linenos">55</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">parse_identifier</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">dialect</span><span class="o">=</span><span class="n">dialect</span><span class="p">)</span>
</span><span id="normalize_identifiers-56"><a href="#normalize_identifiers-56"><span class="linenos">56</span></a>
</span><span id="normalize_identifiers-57"><a href="#normalize_identifiers-57"><span class="linenos">57</span></a> <span class="k">def</span> <span class="nf">_normalize</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">E</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">E</span><span class="p">:</span>
</span><span id="normalize_identifiers-58"><a href="#normalize_identifiers-58"><span class="linenos">58</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">node</span><span class="o">.</span><span class="n">meta</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;case_sensitive&quot;</span><span class="p">):</span>
</span><span id="normalize_identifiers-59"><a href="#normalize_identifiers-59"><span class="linenos">59</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">replace_children</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">_normalize</span><span class="p">)</span>
</span><span id="normalize_identifiers-60"><a href="#normalize_identifiers-60"><span class="linenos">60</span></a> <span class="n">node</span> <span class="o">=</span> <span class="n">dialect</span><span class="o">.</span><span class="n">normalize_identifier</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="normalize_identifiers-61"><a href="#normalize_identifiers-61"><span class="linenos">61</span></a> <span class="k">return</span> <span class="n">node</span>
</span><span id="normalize_identifiers-62"><a href="#normalize_identifiers-62"><span class="linenos">62</span></a>
</span><span id="normalize_identifiers-63"><a href="#normalize_identifiers-63"><span class="linenos">63</span></a> <span class="k">return</span> <span class="n">_normalize</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span></pre></div>

View file

@ -106,15 +106,15 @@
</span><span id="L-48"><a href="#L-48"><span class="linenos">48</span></a><span class="sd"> db: Default database name for tables.</span>
</span><span id="L-49"><a href="#L-49"><span class="linenos">49</span></a><span class="sd"> catalog: Default catalog name for tables.</span>
</span><span id="L-50"><a href="#L-50"><span class="linenos">50</span></a><span class="sd"> schema: Schema to infer column names and types.</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos">51</span></a><span class="sd"> expand_alias_refs: Whether or not to expand references to aliases.</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos">52</span></a><span class="sd"> expand_stars: Whether or not to expand star queries. This is a necessary step</span>
</span><span id="L-51"><a href="#L-51"><span class="linenos">51</span></a><span class="sd"> expand_alias_refs: Whether to expand references to aliases.</span>
</span><span id="L-52"><a href="#L-52"><span class="linenos">52</span></a><span class="sd"> expand_stars: Whether to expand star queries. This is a necessary step</span>
</span><span id="L-53"><a href="#L-53"><span class="linenos">53</span></a><span class="sd"> for most of the optimizer&#39;s rules to work; do not set to False unless you</span>
</span><span id="L-54"><a href="#L-54"><span class="linenos">54</span></a><span class="sd"> know what you&#39;re doing!</span>
</span><span id="L-55"><a href="#L-55"><span class="linenos">55</span></a><span class="sd"> infer_schema: Whether or not to infer the schema if missing.</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos">56</span></a><span class="sd"> isolate_tables: Whether or not to isolate table selects.</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos">57</span></a><span class="sd"> qualify_columns: Whether or not to qualify columns.</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos">58</span></a><span class="sd"> validate_qualify_columns: Whether or not to validate columns.</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos">59</span></a><span class="sd"> quote_identifiers: Whether or not to run the quote_identifiers step.</span>
</span><span id="L-55"><a href="#L-55"><span class="linenos">55</span></a><span class="sd"> infer_schema: Whether to infer the schema if missing.</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos">56</span></a><span class="sd"> isolate_tables: Whether to isolate table selects.</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos">57</span></a><span class="sd"> qualify_columns: Whether to qualify columns.</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos">58</span></a><span class="sd"> validate_qualify_columns: Whether to validate columns.</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos">59</span></a><span class="sd"> quote_identifiers: Whether to run the quote_identifiers step.</span>
</span><span id="L-60"><a href="#L-60"><span class="linenos">60</span></a><span class="sd"> This step is necessary to ensure correctness for case sensitive queries.</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos">61</span></a><span class="sd"> But this flag is provided in case this step is performed at a later time.</span>
</span><span id="L-62"><a href="#L-62"><span class="linenos">62</span></a><span class="sd"> identify: If True, quote all identifiers, else only necessary ones.</span>
@ -195,15 +195,15 @@
</span><span id="qualify-49"><a href="#qualify-49"><span class="linenos">49</span></a><span class="sd"> db: Default database name for tables.</span>
</span><span id="qualify-50"><a href="#qualify-50"><span class="linenos">50</span></a><span class="sd"> catalog: Default catalog name for tables.</span>
</span><span id="qualify-51"><a href="#qualify-51"><span class="linenos">51</span></a><span class="sd"> schema: Schema to infer column names and types.</span>
</span><span id="qualify-52"><a href="#qualify-52"><span class="linenos">52</span></a><span class="sd"> expand_alias_refs: Whether or not to expand references to aliases.</span>
</span><span id="qualify-53"><a href="#qualify-53"><span class="linenos">53</span></a><span class="sd"> expand_stars: Whether or not to expand star queries. This is a necessary step</span>
</span><span id="qualify-52"><a href="#qualify-52"><span class="linenos">52</span></a><span class="sd"> expand_alias_refs: Whether to expand references to aliases.</span>
</span><span id="qualify-53"><a href="#qualify-53"><span class="linenos">53</span></a><span class="sd"> expand_stars: Whether to expand star queries. This is a necessary step</span>
</span><span id="qualify-54"><a href="#qualify-54"><span class="linenos">54</span></a><span class="sd"> for most of the optimizer&#39;s rules to work; do not set to False unless you</span>
</span><span id="qualify-55"><a href="#qualify-55"><span class="linenos">55</span></a><span class="sd"> know what you&#39;re doing!</span>
</span><span id="qualify-56"><a href="#qualify-56"><span class="linenos">56</span></a><span class="sd"> infer_schema: Whether or not to infer the schema if missing.</span>
</span><span id="qualify-57"><a href="#qualify-57"><span class="linenos">57</span></a><span class="sd"> isolate_tables: Whether or not to isolate table selects.</span>
</span><span id="qualify-58"><a href="#qualify-58"><span class="linenos">58</span></a><span class="sd"> qualify_columns: Whether or not to qualify columns.</span>
</span><span id="qualify-59"><a href="#qualify-59"><span class="linenos">59</span></a><span class="sd"> validate_qualify_columns: Whether or not to validate columns.</span>
</span><span id="qualify-60"><a href="#qualify-60"><span class="linenos">60</span></a><span class="sd"> quote_identifiers: Whether or not to run the quote_identifiers step.</span>
</span><span id="qualify-56"><a href="#qualify-56"><span class="linenos">56</span></a><span class="sd"> infer_schema: Whether to infer the schema if missing.</span>
</span><span id="qualify-57"><a href="#qualify-57"><span class="linenos">57</span></a><span class="sd"> isolate_tables: Whether to isolate table selects.</span>
</span><span id="qualify-58"><a href="#qualify-58"><span class="linenos">58</span></a><span class="sd"> qualify_columns: Whether to qualify columns.</span>
</span><span id="qualify-59"><a href="#qualify-59"><span class="linenos">59</span></a><span class="sd"> validate_qualify_columns: Whether to validate columns.</span>
</span><span id="qualify-60"><a href="#qualify-60"><span class="linenos">60</span></a><span class="sd"> quote_identifiers: Whether to run the quote_identifiers step.</span>
</span><span id="qualify-61"><a href="#qualify-61"><span class="linenos">61</span></a><span class="sd"> This step is necessary to ensure correctness for case sensitive queries.</span>
</span><span id="qualify-62"><a href="#qualify-62"><span class="linenos">62</span></a><span class="sd"> But this flag is provided in case this step is performed at a later time.</span>
</span><span id="qualify-63"><a href="#qualify-63"><span class="linenos">63</span></a><span class="sd"> identify: If True, quote all identifiers, else only necessary ones.</span>
@ -264,15 +264,15 @@
<li><strong>db:</strong> Default database name for tables.</li>
<li><strong>catalog:</strong> Default catalog name for tables.</li>
<li><strong>schema:</strong> Schema to infer column names and types.</li>
<li><strong>expand_alias_refs:</strong> Whether or not to expand references to aliases.</li>
<li><strong>expand_stars:</strong> Whether or not to expand star queries. This is a necessary step
<li><strong>expand_alias_refs:</strong> Whether to expand references to aliases.</li>
<li><strong>expand_stars:</strong> Whether to expand star queries. This is a necessary step
for most of the optimizer's rules to work; do not set to False unless you
know what you're doing!</li>
<li><strong>infer_schema:</strong> Whether or not to infer the schema if missing.</li>
<li><strong>isolate_tables:</strong> Whether or not to isolate table selects.</li>
<li><strong>qualify_columns:</strong> Whether or not to qualify columns.</li>
<li><strong>validate_qualify_columns:</strong> Whether or not to validate columns.</li>
<li><strong>quote_identifiers:</strong> Whether or not to run the quote_identifiers step.
<li><strong>infer_schema:</strong> Whether to infer the schema if missing.</li>
<li><strong>isolate_tables:</strong> Whether to isolate table selects.</li>
<li><strong>qualify_columns:</strong> Whether to qualify columns.</li>
<li><strong>validate_qualify_columns:</strong> Whether to validate columns.</li>
<li><strong>quote_identifiers:</strong> Whether to run the quote_identifiers step.
This step is necessary to ensure correctness for case sensitive queries.
But this flag is provided in case this step is performed at a later time.</li>
<li><strong>identify:</strong> If True, quote all identifiers, else only necessary ones.</li>

File diff suppressed because it is too large Load diff

View file

@ -113,8 +113,8 @@
</span><span id="L-55"><a href="#L-55"><span class="linenos"> 55</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;catalog&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">table</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;db&quot;</span><span class="p">):</span>
</span><span id="L-56"><a href="#L-56"><span class="linenos"> 56</span></a> <span class="n">table</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;catalog&quot;</span><span class="p">,</span> <span class="n">catalog</span><span class="p">)</span>
</span><span id="L-57"><a href="#L-57"><span class="linenos"> 57</span></a>
</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">):</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a> <span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">prune</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)):</span>
</span><span id="L-58"><a href="#L-58"><span class="linenos"> 58</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">):</span>
</span><span id="L-59"><a href="#L-59"><span class="linenos"> 59</span></a> <span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">prune</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)):</span>
</span><span id="L-60"><a href="#L-60"><span class="linenos"> 60</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">):</span>
</span><span id="L-61"><a href="#L-61"><span class="linenos"> 61</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-62"><a href="#L-62"><span class="linenos"> 62</span></a>
@ -243,8 +243,8 @@
</span><span id="qualify_tables-56"><a href="#qualify_tables-56"><span class="linenos"> 56</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">table</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;catalog&quot;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">table</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;db&quot;</span><span class="p">):</span>
</span><span id="qualify_tables-57"><a href="#qualify_tables-57"><span class="linenos"> 57</span></a> <span class="n">table</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;catalog&quot;</span><span class="p">,</span> <span class="n">catalog</span><span class="p">)</span>
</span><span id="qualify_tables-58"><a href="#qualify_tables-58"><span class="linenos"> 58</span></a>
</span><span id="qualify_tables-59"><a href="#qualify_tables-59"><span class="linenos"> 59</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">):</span>
</span><span id="qualify_tables-60"><a href="#qualify_tables-60"><span class="linenos"> 60</span></a> <span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">prune</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)):</span>
</span><span id="qualify_tables-59"><a href="#qualify_tables-59"><span class="linenos"> 59</span></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">):</span>
</span><span id="qualify_tables-60"><a href="#qualify_tables-60"><span class="linenos"> 60</span></a> <span class="k">for</span> <span class="n">node</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">prune</span><span class="o">=</span><span class="k">lambda</span> <span class="n">n</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span><span class="p">:</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)):</span>
</span><span id="qualify_tables-61"><a href="#qualify_tables-61"><span class="linenos"> 61</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">):</span>
</span><span id="qualify_tables-62"><a href="#qualify_tables-62"><span class="linenos"> 62</span></a> <span class="n">_qualify</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="qualify_tables-63"><a href="#qualify_tables-63"><span class="linenos"> 63</span></a>

View file

@ -376,7 +376,7 @@
</span><span id="L-138"><a href="#L-138"><span class="linenos">138</span></a> <span class="ow">and</span> <span class="n">_is_derived_table</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-139"><a href="#L-139"><span class="linenos">139</span></a> <span class="p">):</span>
</span><span id="L-140"><a href="#L-140"><span class="linenos">140</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_derived_tables</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">):</span>
</span><span id="L-141"><a href="#L-141"><span class="linenos">141</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UNWRAPPED_QUERIES</span><span class="p">):</span>
</span><span id="L-142"><a href="#L-142"><span class="linenos">142</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_subqueries</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-143"><a href="#L-143"><span class="linenos">143</span></a>
</span><span id="L-144"><a href="#L-144"><span class="linenos">144</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_collected</span> <span class="o">=</span> <span class="kc">True</span>
@ -463,7 +463,7 @@
</span><span id="L-225"><a href="#L-225"><span class="linenos">225</span></a><span class="sd"> SELECT * FROM x WHERE a IN (SELECT ...) &lt;- that&#39;s a subquery</span>
</span><span id="L-226"><a href="#L-226"><span class="linenos">226</span></a>
</span><span id="L-227"><a href="#L-227"><span class="linenos">227</span></a><span class="sd"> Returns:</span>
</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a><span class="sd"> list[exp.Subqueryable]: subqueries</span>
</span><span id="L-228"><a href="#L-228"><span class="linenos">228</span></a><span class="sd"> list[exp.Select | exp.Union]: subqueries</span>
</span><span id="L-229"><a href="#L-229"><span class="linenos">229</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-230"><a href="#L-230"><span class="linenos">230</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_ensure_collected</span><span class="p">()</span>
</span><span id="L-231"><a href="#L-231"><span class="linenos">231</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_subqueries</span>
@ -492,7 +492,7 @@
</span><span id="L-254"><a href="#L-254"><span class="linenos">254</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_columns</span> <span class="o">=</span> <span class="p">[]</span>
</span><span id="L-255"><a href="#L-255"><span class="linenos">255</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span> <span class="o">+</span> <span class="n">external_columns</span><span class="p">:</span>
</span><span id="L-256"><a href="#L-256"><span class="linenos">256</span></a> <span class="n">ancestor</span> <span class="o">=</span> <span class="n">column</span><span class="o">.</span><span class="n">find_ancestor</span><span class="p">(</span>
</span><span id="L-257"><a href="#L-257"><span class="linenos">257</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span>
</span><span id="L-257"><a href="#L-257"><span class="linenos">257</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Star</span>
</span><span id="L-258"><a href="#L-258"><span class="linenos">258</span></a> <span class="p">)</span>
</span><span id="L-259"><a href="#L-259"><span class="linenos">259</span></a> <span class="k">if</span> <span class="p">(</span>
</span><span id="L-260"><a href="#L-260"><span class="linenos">260</span></a> <span class="ow">not</span> <span class="n">ancestor</span>
@ -724,8 +724,8 @@
</span><span id="L-486"><a href="#L-486"><span class="linenos">486</span></a><span class="sd"> Returns:</span>
</span><span id="L-487"><a href="#L-487"><span class="linenos">487</span></a><span class="sd"> list[Scope]: scope instances</span>
</span><span id="L-488"><a href="#L-488"><span class="linenos">488</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-489"><a href="#L-489"><span class="linenos">489</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
</span><span id="L-490"><a href="#L-490"><span class="linenos">490</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">DDL</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)</span>
</span><span id="L-489"><a href="#L-489"><span class="linenos">489</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
</span><span id="L-490"><a href="#L-490"><span class="linenos">490</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">DDL</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)</span>
</span><span id="L-491"><a href="#L-491"><span class="linenos">491</span></a> <span class="p">):</span>
</span><span id="L-492"><a href="#L-492"><span class="linenos">492</span></a> <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">_traverse_scope</span><span class="p">(</span><span class="n">Scope</span><span class="p">(</span><span class="n">expression</span><span class="p">)))</span>
</span><span id="L-493"><a href="#L-493"><span class="linenos">493</span></a>
@ -853,7 +853,7 @@
</span><span id="L-615"><a href="#L-615"><span class="linenos">615</span></a><span class="sd"> as it doesn&#39;t introduce a new scope. If an alias is present, it shadows all names</span>
</span><span id="L-616"><a href="#L-616"><span class="linenos">616</span></a><span class="sd"> under the Subquery, so that&#39;s one exception to this rule.</span>
</span><span id="L-617"><a href="#L-617"><span class="linenos">617</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-618"><a href="#L-618"><span class="linenos">618</span></a> <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">alias</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">))</span>
</span><span id="L-618"><a href="#L-618"><span class="linenos">618</span></a> <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">alias</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UNWRAPPED_QUERIES</span><span class="p">))</span>
</span><span id="L-619"><a href="#L-619"><span class="linenos">619</span></a>
</span><span id="L-620"><a href="#L-620"><span class="linenos">620</span></a>
</span><span id="L-621"><a href="#L-621"><span class="linenos">621</span></a><span class="k">def</span> <span class="nf">_traverse_tables</span><span class="p">(</span><span class="n">scope</span><span class="p">):</span>
@ -1024,7 +1024,7 @@
</span><span id="L-786"><a href="#L-786"><span class="linenos">786</span></a> <span class="ow">and</span> <span class="n">_is_derived_table</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="L-787"><a href="#L-787"><span class="linenos">787</span></a> <span class="p">)</span>
</span><span id="L-788"><a href="#L-788"><span class="linenos">788</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UDTF</span><span class="p">)</span>
</span><span id="L-789"><a href="#L-789"><span class="linenos">789</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">)</span>
</span><span id="L-789"><a href="#L-789"><span class="linenos">789</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UNWRAPPED_QUERIES</span><span class="p">)</span>
</span><span id="L-790"><a href="#L-790"><span class="linenos">790</span></a> <span class="p">):</span>
</span><span id="L-791"><a href="#L-791"><span class="linenos">791</span></a> <span class="n">crossed_scope_boundary</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="L-792"><a href="#L-792"><span class="linenos">792</span></a>
@ -1322,7 +1322,7 @@
</span><span id="Scope-139"><a href="#Scope-139"><span class="linenos">139</span></a> <span class="ow">and</span> <span class="n">_is_derived_table</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="Scope-140"><a href="#Scope-140"><span class="linenos">140</span></a> <span class="p">):</span>
</span><span id="Scope-141"><a href="#Scope-141"><span class="linenos">141</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_derived_tables</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="Scope-142"><a href="#Scope-142"><span class="linenos">142</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">):</span>
</span><span id="Scope-142"><a href="#Scope-142"><span class="linenos">142</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UNWRAPPED_QUERIES</span><span class="p">):</span>
</span><span id="Scope-143"><a href="#Scope-143"><span class="linenos">143</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_subqueries</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="Scope-144"><a href="#Scope-144"><span class="linenos">144</span></a>
</span><span id="Scope-145"><a href="#Scope-145"><span class="linenos">145</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_collected</span> <span class="o">=</span> <span class="kc">True</span>
@ -1409,7 +1409,7 @@
</span><span id="Scope-226"><a href="#Scope-226"><span class="linenos">226</span></a><span class="sd"> SELECT * FROM x WHERE a IN (SELECT ...) &lt;- that&#39;s a subquery</span>
</span><span id="Scope-227"><a href="#Scope-227"><span class="linenos">227</span></a>
</span><span id="Scope-228"><a href="#Scope-228"><span class="linenos">228</span></a><span class="sd"> Returns:</span>
</span><span id="Scope-229"><a href="#Scope-229"><span class="linenos">229</span></a><span class="sd"> list[exp.Subqueryable]: subqueries</span>
</span><span id="Scope-229"><a href="#Scope-229"><span class="linenos">229</span></a><span class="sd"> list[exp.Select | exp.Union]: subqueries</span>
</span><span id="Scope-230"><a href="#Scope-230"><span class="linenos">230</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="Scope-231"><a href="#Scope-231"><span class="linenos">231</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_ensure_collected</span><span class="p">()</span>
</span><span id="Scope-232"><a href="#Scope-232"><span class="linenos">232</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_subqueries</span>
@ -1438,7 +1438,7 @@
</span><span id="Scope-255"><a href="#Scope-255"><span class="linenos">255</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_columns</span> <span class="o">=</span> <span class="p">[]</span>
</span><span id="Scope-256"><a href="#Scope-256"><span class="linenos">256</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span> <span class="o">+</span> <span class="n">external_columns</span><span class="p">:</span>
</span><span id="Scope-257"><a href="#Scope-257"><span class="linenos">257</span></a> <span class="n">ancestor</span> <span class="o">=</span> <span class="n">column</span><span class="o">.</span><span class="n">find_ancestor</span><span class="p">(</span>
</span><span id="Scope-258"><a href="#Scope-258"><span class="linenos">258</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span>
</span><span id="Scope-258"><a href="#Scope-258"><span class="linenos">258</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Star</span>
</span><span id="Scope-259"><a href="#Scope-259"><span class="linenos">259</span></a> <span class="p">)</span>
</span><span id="Scope-260"><a href="#Scope-260"><span class="linenos">260</span></a> <span class="k">if</span> <span class="p">(</span>
</span><span id="Scope-261"><a href="#Scope-261"><span class="linenos">261</span></a> <span class="ow">not</span> <span class="n">ancestor</span>
@ -2183,7 +2183,7 @@ a list of the left and right child scopes.</li>
</span><span id="Scope.subqueries-226"><a href="#Scope.subqueries-226"><span class="linenos">226</span></a><span class="sd"> SELECT * FROM x WHERE a IN (SELECT ...) &lt;- that&#39;s a subquery</span>
</span><span id="Scope.subqueries-227"><a href="#Scope.subqueries-227"><span class="linenos">227</span></a>
</span><span id="Scope.subqueries-228"><a href="#Scope.subqueries-228"><span class="linenos">228</span></a><span class="sd"> Returns:</span>
</span><span id="Scope.subqueries-229"><a href="#Scope.subqueries-229"><span class="linenos">229</span></a><span class="sd"> list[exp.Subqueryable]: subqueries</span>
</span><span id="Scope.subqueries-229"><a href="#Scope.subqueries-229"><span class="linenos">229</span></a><span class="sd"> list[exp.Select | exp.Union]: subqueries</span>
</span><span id="Scope.subqueries-230"><a href="#Scope.subqueries-230"><span class="linenos">230</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="Scope.subqueries-231"><a href="#Scope.subqueries-231"><span class="linenos">231</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_ensure_collected</span><span class="p">()</span>
</span><span id="Scope.subqueries-232"><a href="#Scope.subqueries-232"><span class="linenos">232</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_subqueries</span>
@ -2201,7 +2201,7 @@ a list of the left and right child scopes.</li>
<h6 id="returns">Returns:</h6>
<blockquote>
<p>list[exp.Subqueryable]: subqueries</p>
<p>list[exp.Select | exp.Union]: subqueries</p>
</blockquote>
</div>
@ -2240,7 +2240,7 @@ a list of the left and right child scopes.</li>
</span><span id="Scope.columns-255"><a href="#Scope.columns-255"><span class="linenos">255</span></a> <span class="bp">self</span><span class="o">.</span><span class="n">_columns</span> <span class="o">=</span> <span class="p">[]</span>
</span><span id="Scope.columns-256"><a href="#Scope.columns-256"><span class="linenos">256</span></a> <span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="n">columns</span> <span class="o">+</span> <span class="n">external_columns</span><span class="p">:</span>
</span><span id="Scope.columns-257"><a href="#Scope.columns-257"><span class="linenos">257</span></a> <span class="n">ancestor</span> <span class="o">=</span> <span class="n">column</span><span class="o">.</span><span class="n">find_ancestor</span><span class="p">(</span>
</span><span id="Scope.columns-258"><a href="#Scope.columns-258"><span class="linenos">258</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span>
</span><span id="Scope.columns-258"><a href="#Scope.columns-258"><span class="linenos">258</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Select</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Qualify</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Order</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Having</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Hint</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Table</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Star</span>
</span><span id="Scope.columns-259"><a href="#Scope.columns-259"><span class="linenos">259</span></a> <span class="p">)</span>
</span><span id="Scope.columns-260"><a href="#Scope.columns-260"><span class="linenos">260</span></a> <span class="k">if</span> <span class="p">(</span>
</span><span id="Scope.columns-261"><a href="#Scope.columns-261"><span class="linenos">261</span></a> <span class="ow">not</span> <span class="n">ancestor</span>
@ -2858,8 +2858,8 @@ table only becomes a selected source if it's included in a FROM or JOIN clause.<
</span><span id="traverse_scope-487"><a href="#traverse_scope-487"><span class="linenos">487</span></a><span class="sd"> Returns:</span>
</span><span id="traverse_scope-488"><a href="#traverse_scope-488"><span class="linenos">488</span></a><span class="sd"> list[Scope]: scope instances</span>
</span><span id="traverse_scope-489"><a href="#traverse_scope-489"><span class="linenos">489</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="traverse_scope-490"><a href="#traverse_scope-490"><span class="linenos">490</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
</span><span id="traverse_scope-491"><a href="#traverse_scope-491"><span class="linenos">491</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">DDL</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unionable</span><span class="p">)</span>
</span><span id="traverse_scope-490"><a href="#traverse_scope-490"><span class="linenos">490</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span>
</span><span id="traverse_scope-491"><a href="#traverse_scope-491"><span class="linenos">491</span></a> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">DDL</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Query</span><span class="p">)</span>
</span><span id="traverse_scope-492"><a href="#traverse_scope-492"><span class="linenos">492</span></a> <span class="p">):</span>
</span><span id="traverse_scope-493"><a href="#traverse_scope-493"><span class="linenos">493</span></a> <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">_traverse_scope</span><span class="p">(</span><span class="n">Scope</span><span class="p">(</span><span class="n">expression</span><span class="p">)))</span>
</span><span id="traverse_scope-494"><a href="#traverse_scope-494"><span class="linenos">494</span></a>
@ -2997,7 +2997,7 @@ incomplete properties which is confusing.</p>
</span><span id="walk_in_scope-787"><a href="#walk_in_scope-787"><span class="linenos">787</span></a> <span class="ow">and</span> <span class="n">_is_derived_table</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
</span><span id="walk_in_scope-788"><a href="#walk_in_scope-788"><span class="linenos">788</span></a> <span class="p">)</span>
</span><span id="walk_in_scope-789"><a href="#walk_in_scope-789"><span class="linenos">789</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UDTF</span><span class="p">)</span>
</span><span id="walk_in_scope-790"><a href="#walk_in_scope-790"><span class="linenos">790</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Subqueryable</span><span class="p">)</span>
</span><span id="walk_in_scope-790"><a href="#walk_in_scope-790"><span class="linenos">790</span></a> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">UNWRAPPED_QUERIES</span><span class="p">)</span>
</span><span id="walk_in_scope-791"><a href="#walk_in_scope-791"><span class="linenos">791</span></a> <span class="p">):</span>
</span><span id="walk_in_scope-792"><a href="#walk_in_scope-792"><span class="linenos">792</span></a> <span class="n">crossed_scope_boundary</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="walk_in_scope-793"><a href="#walk_in_scope-793"><span class="linenos">793</span></a>

View file

@ -267,7 +267,7 @@
</span><span id="L-41"><a href="#L-41"><span class="linenos"> 41</span></a>
</span><span id="L-42"><a href="#L-42"><span class="linenos"> 42</span></a><span class="sd"> Args:</span>
</span><span id="L-43"><a href="#L-43"><span class="linenos"> 43</span></a><span class="sd"> expression (sqlglot.Expression): expression to simplify</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="sd"> constant_propagation: whether or not the constant propagation rule should be used</span>
</span><span id="L-44"><a href="#L-44"><span class="linenos"> 44</span></a><span class="sd"> constant_propagation: whether the constant propagation rule should be used</span>
</span><span id="L-45"><a href="#L-45"><span class="linenos"> 45</span></a>
</span><span id="L-46"><a href="#L-46"><span class="linenos"> 46</span></a><span class="sd"> Returns:</span>
</span><span id="L-47"><a href="#L-47"><span class="linenos"> 47</span></a><span class="sd"> sqlglot.Expression: simplified expression</span>
@ -1411,7 +1411,7 @@
</span><span id="L-1185"><a href="#L-1185"><span class="linenos">1185</span></a><span class="n">GEN_MAP</span> <span class="o">=</span> <span class="p">{</span>
</span><span id="L-1186"><a href="#L-1186"><span class="linenos">1186</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Add</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">_binary</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="s2">&quot;+&quot;</span><span class="p">),</span>
</span><span id="L-1187"><a href="#L-1187"><span class="linenos">1187</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">And</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">_binary</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="s2">&quot;AND&quot;</span><span class="p">),</span>
</span><span id="L-1188"><a href="#L-1188"><span class="linenos">1188</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Anonymous</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">e</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
</span><span id="L-1188"><a href="#L-1188"><span class="linenos">1188</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Anonymous</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">_anonymous</span><span class="p">(</span><span class="n">e</span><span class="p">),</span>
</span><span id="L-1189"><a href="#L-1189"><span class="linenos">1189</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Between</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span><span class="si">}</span><span class="s2"> BETWEEN </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;low&#39;</span><span class="p">))</span><span class="si">}</span><span class="s2"> AND </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;high&#39;</span><span class="p">))</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
</span><span id="L-1190"><a href="#L-1190"><span class="linenos">1190</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Boolean</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="s2">&quot;TRUE&quot;</span> <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">this</span> <span class="k">else</span> <span class="s2">&quot;FALSE&quot;</span><span class="p">,</span>
</span><span id="L-1191"><a href="#L-1191"><span class="linenos">1191</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">Bracket</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span><span class="si">}</span><span class="s2">[</span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span><span class="si">}</span><span class="s2">]&quot;</span><span class="p">,</span>
@ -1445,12 +1445,26 @@
</span><span id="L-1219"><a href="#L-1219"><span class="linenos">1219</span></a><span class="p">}</span>
</span><span id="L-1220"><a href="#L-1220"><span class="linenos">1220</span></a>
</span><span id="L-1221"><a href="#L-1221"><span class="linenos">1221</span></a>
</span><span id="L-1222"><a href="#L-1222"><span class="linenos">1222</span></a><span class="k">def</span> <span class="nf">_binary</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Binary</span><span class="p">,</span> <span class="n">op</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-1223"><a href="#L-1223"><span class="linenos">1223</span></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">left</span><span class="p">)</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">op</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">right</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="L-1224"><a href="#L-1224"><span class="linenos">1224</span></a>
</span><span id="L-1225"><a href="#L-1225"><span class="linenos">1225</span></a>
</span><span id="L-1226"><a href="#L-1226"><span class="linenos">1226</span></a><span class="k">def</span> <span class="nf">_unary</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unary</span><span class="p">,</span> <span class="n">op</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-1227"><a href="#L-1227"><span class="linenos">1227</span></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">op</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="L-1222"><a href="#L-1222"><span class="linenos">1222</span></a><span class="k">def</span> <span class="nf">_anonymous</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Anonymous</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-1223"><a href="#L-1223"><span class="linenos">1223</span></a> <span class="n">this</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="n">this</span>
</span><span id="L-1224"><a href="#L-1224"><span class="linenos">1224</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">this</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span><span id="L-1225"><a href="#L-1225"><span class="linenos">1225</span></a> <span class="n">name</span> <span class="o">=</span> <span class="n">this</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
</span><span id="L-1226"><a href="#L-1226"><span class="linenos">1226</span></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Identifier</span><span class="p">):</span>
</span><span id="L-1227"><a href="#L-1227"><span class="linenos">1227</span></a> <span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;&quot;</span><span class="si">{</span><span class="n">this</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s1">&quot;&#39;</span> <span class="k">if</span> <span class="n">this</span><span class="o">.</span><span class="n">quoted</span> <span class="k">else</span> <span class="n">this</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
</span><span id="L-1228"><a href="#L-1228"><span class="linenos">1228</span></a> <span class="k">else</span><span class="p">:</span>
</span><span id="L-1229"><a href="#L-1229"><span class="linenos">1229</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
</span><span id="L-1230"><a href="#L-1230"><span class="linenos">1230</span></a> <span class="sa">f</span><span class="s2">&quot;Anonymous.this expects a str or an Identifier, got &#39;</span><span class="si">{</span><span class="n">this</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">&#39;.&quot;</span>
</span><span id="L-1231"><a href="#L-1231"><span class="linenos">1231</span></a> <span class="p">)</span>
</span><span id="L-1232"><a href="#L-1232"><span class="linenos">1232</span></a>
</span><span id="L-1233"><a href="#L-1233"><span class="linenos">1233</span></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">e</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="L-1234"><a href="#L-1234"><span class="linenos">1234</span></a>
</span><span id="L-1235"><a href="#L-1235"><span class="linenos">1235</span></a>
</span><span id="L-1236"><a href="#L-1236"><span class="linenos">1236</span></a><span class="k">def</span> <span class="nf">_binary</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Binary</span><span class="p">,</span> <span class="n">op</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-1237"><a href="#L-1237"><span class="linenos">1237</span></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">left</span><span class="p">)</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">op</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">right</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span id="L-1238"><a href="#L-1238"><span class="linenos">1238</span></a>
</span><span id="L-1239"><a href="#L-1239"><span class="linenos">1239</span></a>
</span><span id="L-1240"><a href="#L-1240"><span class="linenos">1240</span></a><span class="k">def</span> <span class="nf">_unary</span><span class="p">(</span><span class="n">e</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Unary</span><span class="p">,</span> <span class="n">op</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-1241"><a href="#L-1241"><span class="linenos">1241</span></a> <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">op</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">gen</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
</span></pre></div>
@ -1527,7 +1541,7 @@
</span><span id="simplify-42"><a href="#simplify-42"><span class="linenos"> 42</span></a>
</span><span id="simplify-43"><a href="#simplify-43"><span class="linenos"> 43</span></a><span class="sd"> Args:</span>
</span><span id="simplify-44"><a href="#simplify-44"><span class="linenos"> 44</span></a><span class="sd"> expression (sqlglot.Expression): expression to simplify</span>
</span><span id="simplify-45"><a href="#simplify-45"><span class="linenos"> 45</span></a><span class="sd"> constant_propagation: whether or not the constant propagation rule should be used</span>
</span><span id="simplify-45"><a href="#simplify-45"><span class="linenos"> 45</span></a><span class="sd"> constant_propagation: whether the constant propagation rule should be used</span>
</span><span id="simplify-46"><a href="#simplify-46"><span class="linenos"> 46</span></a>
</span><span id="simplify-47"><a href="#simplify-47"><span class="linenos"> 47</span></a><span class="sd"> Returns:</span>
</span><span id="simplify-48"><a href="#simplify-48"><span class="linenos"> 48</span></a><span class="sd"> sqlglot.Expression: simplified expression</span>
@ -1616,7 +1630,7 @@
<ul>
<li><strong>expression (sqlglot.Expression):</strong> expression to simplify</li>
<li><strong>constant_propagation:</strong> whether or not the constant propagation rule should be used</li>
<li><strong>constant_propagation:</strong> whether the constant propagation rule should be used</li>
</ul>
<h6 id="returns">Returns:</h6>
@ -2546,7 +2560,7 @@ prefix are statically known.</p>
<div class="attr variable">
<span class="name">DATETRUNC_COMPARISONS</span> =
<input id="DATETRUNC_COMPARISONS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DATETRUNC_COMPARISONS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="../expressions.html#GTE">sqlglot.expressions.GTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#EQ">sqlglot.expressions.EQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LT">sqlglot.expressions.LT</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#NEQ">sqlglot.expressions.NEQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GT">sqlglot.expressions.GT</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#In">sqlglot.expressions.In</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LTE">sqlglot.expressions.LTE</a>&#39;&gt;}</span>
<label class="view-value-button pdoc-button" for="DATETRUNC_COMPARISONS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="../expressions.html#In">sqlglot.expressions.In</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GTE">sqlglot.expressions.GTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LTE">sqlglot.expressions.LTE</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#EQ">sqlglot.expressions.EQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#GT">sqlglot.expressions.GT</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#NEQ">sqlglot.expressions.NEQ</a>&#39;&gt;, &lt;class &#39;<a href="../expressions.html#LT">sqlglot.expressions.LT</a>&#39;&gt;}</span>
</div>
@ -2626,7 +2640,7 @@ prefix are statically known.</p>
<section id="JOINS">
<div class="attr variable">
<span class="name">JOINS</span> =
<span class="default_value">{(&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;&#39;, &#39;&#39;)}</span>
<span class="default_value">{(&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;RIGHT&#39;, &#39;&#39;), (&#39;&#39;, &#39;&#39;)}</span>
</div>

View file

@ -312,7 +312,7 @@
</span><span id="L-248"><a href="#L-248"><span class="linenos">248</span></a> <span class="n">key</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="s2">&quot;_x&quot;</span><span class="p">))</span>
</span><span id="L-249"><a href="#L-249"><span class="linenos">249</span></a> <span class="n">parent_predicate</span> <span class="o">=</span> <span class="n">_replace</span><span class="p">(</span>
</span><span id="L-250"><a href="#L-250"><span class="linenos">250</span></a> <span class="n">parent_predicate</span><span class="p">,</span>
</span><span id="L-251"><a href="#L-251"><span class="linenos">251</span></a> <span class="sa">f</span><span class="s1">&#39;(</span><span class="si">{</span><span class="n">parent_predicate</span><span class="si">}</span><span class="s1"> AND ARRAY_ANY(</span><span class="si">{</span><span class="n">nested</span><span class="si">}</span><span class="s1">, &quot;_x&quot; -&gt; </span><span class="si">{</span><span class="n">predicate</span><span class="si">}</span><span class="s1">))&#39;</span><span class="p">,</span>
</span><span id="L-251"><a href="#L-251"><span class="linenos">251</span></a> <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">parent_predicate</span><span class="si">}</span><span class="s2"> AND ARRAY_ANY(</span><span class="si">{</span><span class="n">nested</span><span class="si">}</span><span class="s2">, _x -&gt; </span><span class="si">{</span><span class="n">predicate</span><span class="si">}</span><span class="s2">))&quot;</span><span class="p">,</span>
</span><span id="L-252"><a href="#L-252"><span class="linenos">252</span></a> <span class="p">)</span>
</span><span id="L-253"><a href="#L-253"><span class="linenos">253</span></a>
</span><span id="L-254"><a href="#L-254"><span class="linenos">254</span></a> <span class="n">parent_select</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
@ -662,7 +662,7 @@ Convert correlated or vectorized subqueries into a group by so it is not a many
</span><span id="decorrelate-249"><a href="#decorrelate-249"><span class="linenos">249</span></a> <span class="n">key</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="s2">&quot;_x&quot;</span><span class="p">))</span>
</span><span id="decorrelate-250"><a href="#decorrelate-250"><span class="linenos">250</span></a> <span class="n">parent_predicate</span> <span class="o">=</span> <span class="n">_replace</span><span class="p">(</span>
</span><span id="decorrelate-251"><a href="#decorrelate-251"><span class="linenos">251</span></a> <span class="n">parent_predicate</span><span class="p">,</span>
</span><span id="decorrelate-252"><a href="#decorrelate-252"><span class="linenos">252</span></a> <span class="sa">f</span><span class="s1">&#39;(</span><span class="si">{</span><span class="n">parent_predicate</span><span class="si">}</span><span class="s1"> AND ARRAY_ANY(</span><span class="si">{</span><span class="n">nested</span><span class="si">}</span><span class="s1">, &quot;_x&quot; -&gt; </span><span class="si">{</span><span class="n">predicate</span><span class="si">}</span><span class="s1">))&#39;</span><span class="p">,</span>
</span><span id="decorrelate-252"><a href="#decorrelate-252"><span class="linenos">252</span></a> <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">parent_predicate</span><span class="si">}</span><span class="s2"> AND ARRAY_ANY(</span><span class="si">{</span><span class="n">nested</span><span class="si">}</span><span class="s2">, _x -&gt; </span><span class="si">{</span><span class="n">predicate</span><span class="si">}</span><span class="s2">))&quot;</span><span class="p">,</span>
</span><span id="decorrelate-253"><a href="#decorrelate-253"><span class="linenos">253</span></a> <span class="p">)</span>
</span><span id="decorrelate-254"><a href="#decorrelate-254"><span class="linenos">254</span></a>
</span><span id="decorrelate-255"><a href="#decorrelate-255"><span class="linenos">255</span></a> <span class="n">parent_select</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>

File diff suppressed because one or more lines are too long

View file

@ -264,7 +264,7 @@
</span><span id="L-92"><a href="#L-92"><span class="linenos"> 92</span></a> <span class="n">normalize</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="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="L-93"><a href="#L-93"><span class="linenos"> 93</span></a> <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="L-94"><a href="#L-94"><span class="linenos"> 94</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="sd"> Returns whether or not `column` appears in `table`&#39;s schema.</span>
</span><span id="L-95"><a href="#L-95"><span class="linenos"> 95</span></a><span class="sd"> Returns whether `column` appears in `table`&#39;s schema.</span>
</span><span id="L-96"><a href="#L-96"><span class="linenos"> 96</span></a>
</span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a><span class="sd"> Args:</span>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a><span class="sd"> table: the source table.</span>
@ -287,7 +287,7 @@
</span><span id="L-115"><a href="#L-115"><span class="linenos">115</span></a>
</span><span id="L-116"><a href="#L-116"><span class="linenos">116</span></a> <span class="nd">@property</span>
</span><span id="L-117"><a href="#L-117"><span class="linenos">117</span></a> <span class="k">def</span> <span class="nf">empty</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether or not the schema is empty.&quot;&quot;&quot;</span>
</span><span id="L-118"><a href="#L-118"><span class="linenos">118</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether the schema is empty.&quot;&quot;&quot;</span>
</span><span id="L-119"><a href="#L-119"><span class="linenos">119</span></a> <span class="k">return</span> <span class="kc">True</span>
</span><span id="L-120"><a href="#L-120"><span class="linenos">120</span></a>
</span><span id="L-121"><a href="#L-121"><span class="linenos">121</span></a>
@ -334,7 +334,7 @@
</span><span id="L-162"><a href="#L-162"><span class="linenos">162</span></a>
</span><span id="L-163"><a href="#L-163"><span class="linenos">163</span></a><span class="sd"> Args:</span>
</span><span id="L-164"><a href="#L-164"><span class="linenos">164</span></a><span class="sd"> table: the target table.</span>
</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="sd"> raise_on_missing: whether or not to raise in case the schema is not found.</span>
</span><span id="L-165"><a href="#L-165"><span class="linenos">165</span></a><span class="sd"> raise_on_missing: whether to raise in case the schema is not found.</span>
</span><span id="L-166"><a href="#L-166"><span class="linenos">166</span></a>
</span><span id="L-167"><a href="#L-167"><span class="linenos">167</span></a><span class="sd"> Returns:</span>
</span><span id="L-168"><a href="#L-168"><span class="linenos">168</span></a><span class="sd"> The schema of the target table.</span>
@ -832,7 +832,7 @@
</span><span id="Schema-93"><a href="#Schema-93"><span class="linenos"> 93</span></a> <span class="n">normalize</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="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="Schema-94"><a href="#Schema-94"><span class="linenos"> 94</span></a> <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="Schema-95"><a href="#Schema-95"><span class="linenos"> 95</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="Schema-96"><a href="#Schema-96"><span class="linenos"> 96</span></a><span class="sd"> Returns whether or not `column` appears in `table`&#39;s schema.</span>
</span><span id="Schema-96"><a href="#Schema-96"><span class="linenos"> 96</span></a><span class="sd"> Returns whether `column` appears in `table`&#39;s schema.</span>
</span><span id="Schema-97"><a href="#Schema-97"><span class="linenos"> 97</span></a>
</span><span id="Schema-98"><a href="#Schema-98"><span class="linenos"> 98</span></a><span class="sd"> Args:</span>
</span><span id="Schema-99"><a href="#Schema-99"><span class="linenos"> 99</span></a><span class="sd"> table: the source table.</span>
@ -855,7 +855,7 @@
</span><span id="Schema-116"><a href="#Schema-116"><span class="linenos">116</span></a>
</span><span id="Schema-117"><a href="#Schema-117"><span class="linenos">117</span></a> <span class="nd">@property</span>
</span><span id="Schema-118"><a href="#Schema-118"><span class="linenos">118</span></a> <span class="k">def</span> <span class="nf">empty</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="Schema-119"><a href="#Schema-119"><span class="linenos">119</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether or not the schema is empty.&quot;&quot;&quot;</span>
</span><span id="Schema-119"><a href="#Schema-119"><span class="linenos">119</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether the schema is empty.&quot;&quot;&quot;</span>
</span><span id="Schema-120"><a href="#Schema-120"><span class="linenos">120</span></a> <span class="k">return</span> <span class="kc">True</span>
</span></pre></div>
@ -1055,7 +1055,7 @@ The added table must have the necessary number of qualifiers in its path to matc
</span><span id="Schema.has_column-93"><a href="#Schema.has_column-93"><span class="linenos"> 93</span></a> <span class="n">normalize</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="nb">bool</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
</span><span id="Schema.has_column-94"><a href="#Schema.has_column-94"><span class="linenos"> 94</span></a> <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="Schema.has_column-95"><a href="#Schema.has_column-95"><span class="linenos"> 95</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="Schema.has_column-96"><a href="#Schema.has_column-96"><span class="linenos"> 96</span></a><span class="sd"> Returns whether or not `column` appears in `table`&#39;s schema.</span>
</span><span id="Schema.has_column-96"><a href="#Schema.has_column-96"><span class="linenos"> 96</span></a><span class="sd"> Returns whether `column` appears in `table`&#39;s schema.</span>
</span><span id="Schema.has_column-97"><a href="#Schema.has_column-97"><span class="linenos"> 97</span></a>
</span><span id="Schema.has_column-98"><a href="#Schema.has_column-98"><span class="linenos"> 98</span></a><span class="sd"> Args:</span>
</span><span id="Schema.has_column-99"><a href="#Schema.has_column-99"><span class="linenos"> 99</span></a><span class="sd"> table: the source table.</span>
@ -1071,7 +1071,7 @@ The added table must have the necessary number of qualifiers in its path to matc
</span></pre></div>
<div class="docstring"><p>Returns whether or not <code>column</code> appears in <code>table</code>'s schema.</p>
<div class="docstring"><p>Returns whether <code>column</code> appears in <code>table</code>'s schema.</p>
<h6 id="arguments">Arguments:</h6>
@ -1125,12 +1125,12 @@ The added table must have the necessary number of qualifiers in its path to matc
<a class="headerlink" href="#Schema.empty"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="Schema.empty-117"><a href="#Schema.empty-117"><span class="linenos">117</span></a> <span class="nd">@property</span>
</span><span id="Schema.empty-118"><a href="#Schema.empty-118"><span class="linenos">118</span></a> <span class="k">def</span> <span class="nf">empty</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span><span id="Schema.empty-119"><a href="#Schema.empty-119"><span class="linenos">119</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether or not the schema is empty.&quot;&quot;&quot;</span>
</span><span id="Schema.empty-119"><a href="#Schema.empty-119"><span class="linenos">119</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns whether the schema is empty.&quot;&quot;&quot;</span>
</span><span id="Schema.empty-120"><a href="#Schema.empty-120"><span class="linenos">120</span></a> <span class="k">return</span> <span class="kc">True</span>
</span></pre></div>
<div class="docstring"><p>Returns whether or not the schema is empty.</p>
<div class="docstring"><p>Returns whether the schema is empty.</p>
</div>
@ -1190,7 +1190,7 @@ The added table must have the necessary number of qualifiers in its path to matc
</span><span id="AbstractMappingSchema-163"><a href="#AbstractMappingSchema-163"><span class="linenos">163</span></a>
</span><span id="AbstractMappingSchema-164"><a href="#AbstractMappingSchema-164"><span class="linenos">164</span></a><span class="sd"> Args:</span>
</span><span id="AbstractMappingSchema-165"><a href="#AbstractMappingSchema-165"><span class="linenos">165</span></a><span class="sd"> table: the target table.</span>
</span><span id="AbstractMappingSchema-166"><a href="#AbstractMappingSchema-166"><span class="linenos">166</span></a><span class="sd"> raise_on_missing: whether or not to raise in case the schema is not found.</span>
</span><span id="AbstractMappingSchema-166"><a href="#AbstractMappingSchema-166"><span class="linenos">166</span></a><span class="sd"> raise_on_missing: whether to raise in case the schema is not found.</span>
</span><span id="AbstractMappingSchema-167"><a href="#AbstractMappingSchema-167"><span class="linenos">167</span></a>
</span><span id="AbstractMappingSchema-168"><a href="#AbstractMappingSchema-168"><span class="linenos">168</span></a><span class="sd"> Returns:</span>
</span><span id="AbstractMappingSchema-169"><a href="#AbstractMappingSchema-169"><span class="linenos">169</span></a><span class="sd"> The schema of the target table.</span>
@ -1377,7 +1377,7 @@ The added table must have the necessary number of qualifiers in its path to matc
</span><span id="AbstractMappingSchema.find-163"><a href="#AbstractMappingSchema.find-163"><span class="linenos">163</span></a>
</span><span id="AbstractMappingSchema.find-164"><a href="#AbstractMappingSchema.find-164"><span class="linenos">164</span></a><span class="sd"> Args:</span>
</span><span id="AbstractMappingSchema.find-165"><a href="#AbstractMappingSchema.find-165"><span class="linenos">165</span></a><span class="sd"> table: the target table.</span>
</span><span id="AbstractMappingSchema.find-166"><a href="#AbstractMappingSchema.find-166"><span class="linenos">166</span></a><span class="sd"> raise_on_missing: whether or not to raise in case the schema is not found.</span>
</span><span id="AbstractMappingSchema.find-166"><a href="#AbstractMappingSchema.find-166"><span class="linenos">166</span></a><span class="sd"> raise_on_missing: whether to raise in case the schema is not found.</span>
</span><span id="AbstractMappingSchema.find-167"><a href="#AbstractMappingSchema.find-167"><span class="linenos">167</span></a>
</span><span id="AbstractMappingSchema.find-168"><a href="#AbstractMappingSchema.find-168"><span class="linenos">168</span></a><span class="sd"> Returns:</span>
</span><span id="AbstractMappingSchema.find-169"><a href="#AbstractMappingSchema.find-169"><span class="linenos">169</span></a><span class="sd"> The schema of the target table.</span>
@ -1409,7 +1409,7 @@ The added table must have the necessary number of qualifiers in its path to matc
<ul>
<li><strong>table:</strong> the target table.</li>
<li><strong>raise_on_missing:</strong> whether or not to raise in case the schema is not found.</li>
<li><strong>raise_on_missing:</strong> whether to raise in case the schema is not found.</li>
</ul>
<h6 id="returns">Returns:</h6>
@ -2062,7 +2062,7 @@ The added table must have the necessary number of qualifiers in its path to matc
</span></pre></div>
<div class="docstring"><p>Returns whether or not <code>column</code> appears in <code>table</code>'s schema.</p>
<div class="docstring"><p>Returns whether <code>column</code> appears in <code>table</code>'s schema.</p>
<h6 id="arguments">Arguments:</h6>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -90,6 +90,9 @@
<li>
<a class="function" href="#move_partitioned_by_to_schema_columns">move_partitioned_by_to_schema_columns</a>
</li>
<li>
<a class="function" href="#struct_kv_to_alias">struct_kv_to_alias</a>
</li>
<li>
<a class="function" href="#preprocess">preprocess</a>
</li>
@ -665,7 +668,7 @@
</span><span id="L-547"><a href="#L-547"><span class="linenos">547</span></a> <span class="n">prop</span>
</span><span id="L-548"><a href="#L-548"><span class="linenos">548</span></a> <span class="ow">and</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span>
</span><span id="L-549"><a href="#L-549"><span class="linenos">549</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Schema</span><span class="p">)</span>
</span><span id="L-550"><a href="#L-550"><span class="linenos">550</span></a> <span class="ow">and</span> <span class="nb">all</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ColumnDef</span><span class="p">)</span> <span class="ow">and</span> <span class="n">e</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;kind&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span>
</span><span id="L-550"><a href="#L-550"><span class="linenos">550</span></a> <span class="ow">and</span> <span class="nb">all</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ColumnDef</span><span class="p">)</span> <span class="ow">and</span> <span class="n">e</span><span class="o">.</span><span class="n">kind</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span>
</span><span id="L-551"><a href="#L-551"><span class="linenos">551</span></a> <span class="p">):</span>
</span><span id="L-552"><a href="#L-552"><span class="linenos">552</span></a> <span class="n">prop_this</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Tuple</span><span class="p">(</span>
</span><span id="L-553"><a href="#L-553"><span class="linenos">553</span></a> <span class="n">expressions</span><span class="o">=</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">]</span>
@ -678,50 +681,66 @@
</span><span id="L-560"><a href="#L-560"><span class="linenos">560</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="L-561"><a href="#L-561"><span class="linenos">561</span></a>
</span><span id="L-562"><a href="#L-562"><span class="linenos">562</span></a>
</span><span id="L-563"><a href="#L-563"><span class="linenos">563</span></a><span class="k">def</span> <span class="nf">preprocess</span><span class="p">(</span>
</span><span id="L-564"><a href="#L-564"><span class="linenos">564</span></a> <span class="n">transforms</span><span class="p">:</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">Callable</span><span class="p">[[</span><span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">]],</span>
</span><span id="L-565"><a href="#L-565"><span class="linenos">565</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Callable</span><span class="p">[[</span><span class="n">Generator</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="L-566"><a href="#L-566"><span class="linenos">566</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-567"><a href="#L-567"><span class="linenos">567</span></a><span class="sd"> Creates a new transform by chaining a sequence of transformations and converts the resulting</span>
</span><span id="L-568"><a href="#L-568"><span class="linenos">568</span></a><span class="sd"> expression to SQL, using either the &quot;_sql&quot; method corresponding to the resulting expression,</span>
</span><span id="L-569"><a href="#L-569"><span class="linenos">569</span></a><span class="sd"> or the appropriate `Generator.TRANSFORMS` function (when applicable -- see below).</span>
</span><span id="L-570"><a href="#L-570"><span class="linenos">570</span></a>
</span><span id="L-571"><a href="#L-571"><span class="linenos">571</span></a><span class="sd"> Args:</span>
</span><span id="L-572"><a href="#L-572"><span class="linenos">572</span></a><span class="sd"> transforms: sequence of transform functions. These will be called in order.</span>
</span><span id="L-573"><a href="#L-573"><span class="linenos">573</span></a>
</span><span id="L-574"><a href="#L-574"><span class="linenos">574</span></a><span class="sd"> Returns:</span>
</span><span id="L-575"><a href="#L-575"><span class="linenos">575</span></a><span class="sd"> Function that can be used as a generator transform.</span>
</span><span id="L-576"><a href="#L-576"><span class="linenos">576</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-563"><a href="#L-563"><span class="linenos">563</span></a><span class="k">def</span> <span class="nf">struct_kv_to_alias</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">:</span>
</span><span id="L-564"><a href="#L-564"><span class="linenos">564</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-565"><a href="#L-565"><span class="linenos">565</span></a><span class="sd"> Convert struct arguments to aliases: STRUCT(1 AS y) .</span>
</span><span id="L-566"><a href="#L-566"><span class="linenos">566</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-567"><a href="#L-567"><span class="linenos">567</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Struct</span><span class="p">):</span>
</span><span id="L-568"><a href="#L-568"><span class="linenos">568</span></a> <span class="n">expression</span><span class="o">.</span><span class="n">set</span><span class="p">(</span>
</span><span id="L-569"><a href="#L-569"><span class="linenos">569</span></a> <span class="s2">&quot;expressions&quot;</span><span class="p">,</span>
</span><span id="L-570"><a href="#L-570"><span class="linenos">570</span></a> <span class="p">[</span>
</span><span id="L-571"><a href="#L-571"><span class="linenos">571</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">alias_</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">PropertyEQ</span><span class="p">)</span> <span class="k">else</span> <span class="n">e</span>
</span><span id="L-572"><a href="#L-572"><span class="linenos">572</span></a> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">expressions</span>
</span><span id="L-573"><a href="#L-573"><span class="linenos">573</span></a> <span class="p">],</span>
</span><span id="L-574"><a href="#L-574"><span class="linenos">574</span></a> <span class="p">)</span>
</span><span id="L-575"><a href="#L-575"><span class="linenos">575</span></a>
</span><span id="L-576"><a href="#L-576"><span class="linenos">576</span></a> <span class="k">return</span> <span class="n">expression</span>
</span><span id="L-577"><a href="#L-577"><span class="linenos">577</span></a>
</span><span id="L-578"><a href="#L-578"><span class="linenos">578</span></a> <span class="k">def</span> <span class="nf">_to_sql</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-579"><a href="#L-579"><span class="linenos">579</span></a> <span class="n">expression_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-580"><a href="#L-580"><span class="linenos">580</span></a>
</span><span id="L-581"><a href="#L-581"><span class="linenos">581</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-582"><a href="#L-582"><span class="linenos">582</span></a> <span class="k">for</span> <span class="n">transform</span> <span class="ow">in</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="L-583"><a href="#L-583"><span class="linenos">583</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-584"><a href="#L-584"><span class="linenos">584</span></a>
</span><span id="L-585"><a href="#L-585"><span class="linenos">585</span></a> <span class="n">_sql_handler</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="o">.</span><span class="n">key</span> <span class="o">+</span> <span class="s2">&quot;_sql&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="L-586"><a href="#L-586"><span class="linenos">586</span></a> <span class="k">if</span> <span class="n">_sql_handler</span><span class="p">:</span>
</span><span id="L-587"><a href="#L-587"><span class="linenos">587</span></a> <span class="k">return</span> <span class="n">_sql_handler</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-588"><a href="#L-588"><span class="linenos">588</span></a>
</span><span id="L-589"><a href="#L-589"><span class="linenos">589</span></a> <span class="n">transforms_handler</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">TRANSFORMS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">))</span>
</span><span id="L-590"><a href="#L-590"><span class="linenos">590</span></a> <span class="k">if</span> <span class="n">transforms_handler</span><span class="p">:</span>
</span><span id="L-591"><a href="#L-591"><span class="linenos">591</span></a> <span class="k">if</span> <span class="n">expression_type</span> <span class="ow">is</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">):</span>
</span><span id="L-592"><a href="#L-592"><span class="linenos">592</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Func</span><span class="p">):</span>
</span><span id="L-593"><a href="#L-593"><span class="linenos">593</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">function_fallback_sql</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-594"><a href="#L-594"><span class="linenos">594</span></a>
</span><span id="L-595"><a href="#L-595"><span class="linenos">595</span></a> <span class="c1"># Ensures we don&#39;t enter an infinite loop. This can happen when the original expression</span>
</span><span id="L-596"><a href="#L-596"><span class="linenos">596</span></a> <span class="c1"># has the same type as the final expression and there&#39;s no _sql method available for it,</span>
</span><span id="L-597"><a href="#L-597"><span class="linenos">597</span></a> <span class="c1"># because then it&#39;d re-enter _to_sql.</span>
</span><span id="L-598"><a href="#L-598"><span class="linenos">598</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
</span><span id="L-599"><a href="#L-599"><span class="linenos">599</span></a> <span class="sa">f</span><span class="s2">&quot;Expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> requires a _sql method in order to be transformed.&quot;</span>
</span><span id="L-600"><a href="#L-600"><span class="linenos">600</span></a> <span class="p">)</span>
</span><span id="L-601"><a href="#L-601"><span class="linenos">601</span></a>
</span><span id="L-602"><a href="#L-602"><span class="linenos">602</span></a> <span class="k">return</span> <span class="n">transforms_handler</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
</span><span id="L-603"><a href="#L-603"><span class="linenos">603</span></a>
</span><span id="L-604"><a href="#L-604"><span class="linenos">604</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</span><span id="L-605"><a href="#L-605"><span class="linenos">605</span></a>
</span><span id="L-606"><a href="#L-606"><span class="linenos">606</span></a> <span class="k">return</span> <span class="n">_to_sql</span>
</span><span id="L-578"><a href="#L-578"><span class="linenos">578</span></a>
</span><span id="L-579"><a href="#L-579"><span class="linenos">579</span></a><span class="k">def</span> <span class="nf">preprocess</span><span class="p">(</span>
</span><span id="L-580"><a href="#L-580"><span class="linenos">580</span></a> <span class="n">transforms</span><span class="p">:</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">Callable</span><span class="p">[[</span><span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">]],</span>
</span><span id="L-581"><a href="#L-581"><span class="linenos">581</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Callable</span><span class="p">[[</span><span class="n">Generator</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="L-582"><a href="#L-582"><span class="linenos">582</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="L-583"><a href="#L-583"><span class="linenos">583</span></a><span class="sd"> Creates a new transform by chaining a sequence of transformations and converts the resulting</span>
</span><span id="L-584"><a href="#L-584"><span class="linenos">584</span></a><span class="sd"> expression to SQL, using either the &quot;_sql&quot; method corresponding to the resulting expression,</span>
</span><span id="L-585"><a href="#L-585"><span class="linenos">585</span></a><span class="sd"> or the appropriate `Generator.TRANSFORMS` function (when applicable -- see below).</span>
</span><span id="L-586"><a href="#L-586"><span class="linenos">586</span></a>
</span><span id="L-587"><a href="#L-587"><span class="linenos">587</span></a><span class="sd"> Args:</span>
</span><span id="L-588"><a href="#L-588"><span class="linenos">588</span></a><span class="sd"> transforms: sequence of transform functions. These will be called in order.</span>
</span><span id="L-589"><a href="#L-589"><span class="linenos">589</span></a>
</span><span id="L-590"><a href="#L-590"><span class="linenos">590</span></a><span class="sd"> Returns:</span>
</span><span id="L-591"><a href="#L-591"><span class="linenos">591</span></a><span class="sd"> Function that can be used as a generator transform.</span>
</span><span id="L-592"><a href="#L-592"><span class="linenos">592</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="L-593"><a href="#L-593"><span class="linenos">593</span></a>
</span><span id="L-594"><a href="#L-594"><span class="linenos">594</span></a> <span class="k">def</span> <span class="nf">_to_sql</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="L-595"><a href="#L-595"><span class="linenos">595</span></a> <span class="n">expression_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-596"><a href="#L-596"><span class="linenos">596</span></a>
</span><span id="L-597"><a href="#L-597"><span class="linenos">597</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-598"><a href="#L-598"><span class="linenos">598</span></a> <span class="k">for</span> <span class="n">transform</span> <span class="ow">in</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="L-599"><a href="#L-599"><span class="linenos">599</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-600"><a href="#L-600"><span class="linenos">600</span></a>
</span><span id="L-601"><a href="#L-601"><span class="linenos">601</span></a> <span class="n">_sql_handler</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="o">.</span><span class="n">key</span> <span class="o">+</span> <span class="s2">&quot;_sql&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="L-602"><a href="#L-602"><span class="linenos">602</span></a> <span class="k">if</span> <span class="n">_sql_handler</span><span class="p">:</span>
</span><span id="L-603"><a href="#L-603"><span class="linenos">603</span></a> <span class="k">return</span> <span class="n">_sql_handler</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-604"><a href="#L-604"><span class="linenos">604</span></a>
</span><span id="L-605"><a href="#L-605"><span class="linenos">605</span></a> <span class="n">transforms_handler</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">TRANSFORMS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">))</span>
</span><span id="L-606"><a href="#L-606"><span class="linenos">606</span></a> <span class="k">if</span> <span class="n">transforms_handler</span><span class="p">:</span>
</span><span id="L-607"><a href="#L-607"><span class="linenos">607</span></a> <span class="k">if</span> <span class="n">expression_type</span> <span class="ow">is</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">):</span>
</span><span id="L-608"><a href="#L-608"><span class="linenos">608</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Func</span><span class="p">):</span>
</span><span id="L-609"><a href="#L-609"><span class="linenos">609</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">function_fallback_sql</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="L-610"><a href="#L-610"><span class="linenos">610</span></a>
</span><span id="L-611"><a href="#L-611"><span class="linenos">611</span></a> <span class="c1"># Ensures we don&#39;t enter an infinite loop. This can happen when the original expression</span>
</span><span id="L-612"><a href="#L-612"><span class="linenos">612</span></a> <span class="c1"># has the same type as the final expression and there&#39;s no _sql method available for it,</span>
</span><span id="L-613"><a href="#L-613"><span class="linenos">613</span></a> <span class="c1"># because then it&#39;d re-enter _to_sql.</span>
</span><span id="L-614"><a href="#L-614"><span class="linenos">614</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
</span><span id="L-615"><a href="#L-615"><span class="linenos">615</span></a> <span class="sa">f</span><span class="s2">&quot;Expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> requires a _sql method in order to be transformed.&quot;</span>
</span><span id="L-616"><a href="#L-616"><span class="linenos">616</span></a> <span class="p">)</span>
</span><span id="L-617"><a href="#L-617"><span class="linenos">617</span></a>
</span><span id="L-618"><a href="#L-618"><span class="linenos">618</span></a> <span class="k">return</span> <span class="n">transforms_handler</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
</span><span id="L-619"><a href="#L-619"><span class="linenos">619</span></a>
</span><span id="L-620"><a href="#L-620"><span class="linenos">620</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</span><span id="L-621"><a href="#L-621"><span class="linenos">621</span></a>
</span><span id="L-622"><a href="#L-622"><span class="linenos">622</span></a> <span class="k">return</span> <span class="n">_to_sql</span>
</span></pre></div>
@ -1643,7 +1662,7 @@ The corresponding columns are removed from the create statement.</p>
</span><span id="move_partitioned_by_to_schema_columns-548"><a href="#move_partitioned_by_to_schema_columns-548"><span class="linenos">548</span></a> <span class="n">prop</span>
</span><span id="move_partitioned_by_to_schema_columns-549"><a href="#move_partitioned_by_to_schema_columns-549"><span class="linenos">549</span></a> <span class="ow">and</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span>
</span><span id="move_partitioned_by_to_schema_columns-550"><a href="#move_partitioned_by_to_schema_columns-550"><span class="linenos">550</span></a> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Schema</span><span class="p">)</span>
</span><span id="move_partitioned_by_to_schema_columns-551"><a href="#move_partitioned_by_to_schema_columns-551"><span class="linenos">551</span></a> <span class="ow">and</span> <span class="nb">all</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ColumnDef</span><span class="p">)</span> <span class="ow">and</span> <span class="n">e</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;kind&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span>
</span><span id="move_partitioned_by_to_schema_columns-551"><a href="#move_partitioned_by_to_schema_columns-551"><span class="linenos">551</span></a> <span class="ow">and</span> <span class="nb">all</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">ColumnDef</span><span class="p">)</span> <span class="ow">and</span> <span class="n">e</span><span class="o">.</span><span class="n">kind</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">)</span>
</span><span id="move_partitioned_by_to_schema_columns-552"><a href="#move_partitioned_by_to_schema_columns-552"><span class="linenos">552</span></a> <span class="p">):</span>
</span><span id="move_partitioned_by_to_schema_columns-553"><a href="#move_partitioned_by_to_schema_columns-553"><span class="linenos">553</span></a> <span class="n">prop_this</span> <span class="o">=</span> <span class="n">exp</span><span class="o">.</span><span class="n">Tuple</span><span class="p">(</span>
</span><span id="move_partitioned_by_to_schema_columns-554"><a href="#move_partitioned_by_to_schema_columns-554"><span class="linenos">554</span></a> <span class="n">expressions</span><span class="o">=</span><span class="p">[</span><span class="n">exp</span><span class="o">.</span><span class="n">to_identifier</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">prop</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">expressions</span><span class="p">]</span>
@ -1663,6 +1682,39 @@ The corresponding columns are removed from the create statement.</p>
</div>
</section>
<section id="struct_kv_to_alias">
<input id="struct_kv_to_alias-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<div class="attr function">
<span class="def">def</span>
<span class="name">struct_kv_to_alias</span><span class="signature pdoc-code multiline">(<span class="param"> <span class="n">expression</span><span class="p">:</span> <span class="n"><a href="expressions.html#Expression">sqlglot.expressions.Expression</a></span></span><span class="return-annotation">) -> <span class="n"><a href="expressions.html#Expression">sqlglot.expressions.Expression</a></span>:</span></span>
<label class="view-source-button" for="struct_kv_to_alias-view-source"><span>View Source</span></label>
</div>
<a class="headerlink" href="#struct_kv_to_alias"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="struct_kv_to_alias-564"><a href="#struct_kv_to_alias-564"><span class="linenos">564</span></a><span class="k">def</span> <span class="nf">struct_kv_to_alias</span><span class="p">(</span><span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">:</span>
</span><span id="struct_kv_to_alias-565"><a href="#struct_kv_to_alias-565"><span class="linenos">565</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="struct_kv_to_alias-566"><a href="#struct_kv_to_alias-566"><span class="linenos">566</span></a><span class="sd"> Convert struct arguments to aliases: STRUCT(1 AS y) .</span>
</span><span id="struct_kv_to_alias-567"><a href="#struct_kv_to_alias-567"><span class="linenos">567</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="struct_kv_to_alias-568"><a href="#struct_kv_to_alias-568"><span class="linenos">568</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Struct</span><span class="p">):</span>
</span><span id="struct_kv_to_alias-569"><a href="#struct_kv_to_alias-569"><span class="linenos">569</span></a> <span class="n">expression</span><span class="o">.</span><span class="n">set</span><span class="p">(</span>
</span><span id="struct_kv_to_alias-570"><a href="#struct_kv_to_alias-570"><span class="linenos">570</span></a> <span class="s2">&quot;expressions&quot;</span><span class="p">,</span>
</span><span id="struct_kv_to_alias-571"><a href="#struct_kv_to_alias-571"><span class="linenos">571</span></a> <span class="p">[</span>
</span><span id="struct_kv_to_alias-572"><a href="#struct_kv_to_alias-572"><span class="linenos">572</span></a> <span class="n">exp</span><span class="o">.</span><span class="n">alias_</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">expression</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">this</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">PropertyEQ</span><span class="p">)</span> <span class="k">else</span> <span class="n">e</span>
</span><span id="struct_kv_to_alias-573"><a href="#struct_kv_to_alias-573"><span class="linenos">573</span></a> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">expression</span><span class="o">.</span><span class="n">expressions</span>
</span><span id="struct_kv_to_alias-574"><a href="#struct_kv_to_alias-574"><span class="linenos">574</span></a> <span class="p">],</span>
</span><span id="struct_kv_to_alias-575"><a href="#struct_kv_to_alias-575"><span class="linenos">575</span></a> <span class="p">)</span>
</span><span id="struct_kv_to_alias-576"><a href="#struct_kv_to_alias-576"><span class="linenos">576</span></a>
</span><span id="struct_kv_to_alias-577"><a href="#struct_kv_to_alias-577"><span class="linenos">577</span></a> <span class="k">return</span> <span class="n">expression</span>
</span></pre></div>
<div class="docstring"><p>Convert struct arguments to aliases: STRUCT(1 AS y) .</p>
</div>
</section>
<section id="preprocess">
<input id="preprocess-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
@ -1675,50 +1727,50 @@ The corresponding columns are removed from the create statement.</p>
</div>
<a class="headerlink" href="#preprocess"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="preprocess-564"><a href="#preprocess-564"><span class="linenos">564</span></a><span class="k">def</span> <span class="nf">preprocess</span><span class="p">(</span>
</span><span id="preprocess-565"><a href="#preprocess-565"><span class="linenos">565</span></a> <span class="n">transforms</span><span class="p">:</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">Callable</span><span class="p">[[</span><span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">]],</span>
</span><span id="preprocess-566"><a href="#preprocess-566"><span class="linenos">566</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Callable</span><span class="p">[[</span><span class="n">Generator</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="preprocess-567"><a href="#preprocess-567"><span class="linenos">567</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="preprocess-568"><a href="#preprocess-568"><span class="linenos">568</span></a><span class="sd"> Creates a new transform by chaining a sequence of transformations and converts the resulting</span>
</span><span id="preprocess-569"><a href="#preprocess-569"><span class="linenos">569</span></a><span class="sd"> expression to SQL, using either the &quot;_sql&quot; method corresponding to the resulting expression,</span>
</span><span id="preprocess-570"><a href="#preprocess-570"><span class="linenos">570</span></a><span class="sd"> or the appropriate `Generator.TRANSFORMS` function (when applicable -- see below).</span>
</span><span id="preprocess-571"><a href="#preprocess-571"><span class="linenos">571</span></a>
</span><span id="preprocess-572"><a href="#preprocess-572"><span class="linenos">572</span></a><span class="sd"> Args:</span>
</span><span id="preprocess-573"><a href="#preprocess-573"><span class="linenos">573</span></a><span class="sd"> transforms: sequence of transform functions. These will be called in order.</span>
</span><span id="preprocess-574"><a href="#preprocess-574"><span class="linenos">574</span></a>
</span><span id="preprocess-575"><a href="#preprocess-575"><span class="linenos">575</span></a><span class="sd"> Returns:</span>
</span><span id="preprocess-576"><a href="#preprocess-576"><span class="linenos">576</span></a><span class="sd"> Function that can be used as a generator transform.</span>
</span><span id="preprocess-577"><a href="#preprocess-577"><span class="linenos">577</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="preprocess-578"><a href="#preprocess-578"><span class="linenos">578</span></a>
</span><span id="preprocess-579"><a href="#preprocess-579"><span class="linenos">579</span></a> <span class="k">def</span> <span class="nf">_to_sql</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="preprocess-580"><a href="#preprocess-580"><span class="linenos">580</span></a> <span class="n">expression_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-581"><a href="#preprocess-581"><span class="linenos">581</span></a>
</span><span id="preprocess-582"><a href="#preprocess-582"><span class="linenos">582</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-583"><a href="#preprocess-583"><span class="linenos">583</span></a> <span class="k">for</span> <span class="n">transform</span> <span class="ow">in</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="preprocess-584"><a href="#preprocess-584"><span class="linenos">584</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-585"><a href="#preprocess-585"><span class="linenos">585</span></a>
</span><span id="preprocess-586"><a href="#preprocess-586"><span class="linenos">586</span></a> <span class="n">_sql_handler</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="o">.</span><span class="n">key</span> <span class="o">+</span> <span class="s2">&quot;_sql&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="preprocess-587"><a href="#preprocess-587"><span class="linenos">587</span></a> <span class="k">if</span> <span class="n">_sql_handler</span><span class="p">:</span>
</span><span id="preprocess-588"><a href="#preprocess-588"><span class="linenos">588</span></a> <span class="k">return</span> <span class="n">_sql_handler</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-589"><a href="#preprocess-589"><span class="linenos">589</span></a>
</span><span id="preprocess-590"><a href="#preprocess-590"><span class="linenos">590</span></a> <span class="n">transforms_handler</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">TRANSFORMS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">))</span>
</span><span id="preprocess-591"><a href="#preprocess-591"><span class="linenos">591</span></a> <span class="k">if</span> <span class="n">transforms_handler</span><span class="p">:</span>
</span><span id="preprocess-592"><a href="#preprocess-592"><span class="linenos">592</span></a> <span class="k">if</span> <span class="n">expression_type</span> <span class="ow">is</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">):</span>
</span><span id="preprocess-593"><a href="#preprocess-593"><span class="linenos">593</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Func</span><span class="p">):</span>
</span><span id="preprocess-594"><a href="#preprocess-594"><span class="linenos">594</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">function_fallback_sql</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-595"><a href="#preprocess-595"><span class="linenos">595</span></a>
</span><span id="preprocess-596"><a href="#preprocess-596"><span class="linenos">596</span></a> <span class="c1"># Ensures we don&#39;t enter an infinite loop. This can happen when the original expression</span>
</span><span id="preprocess-597"><a href="#preprocess-597"><span class="linenos">597</span></a> <span class="c1"># has the same type as the final expression and there&#39;s no _sql method available for it,</span>
</span><span id="preprocess-598"><a href="#preprocess-598"><span class="linenos">598</span></a> <span class="c1"># because then it&#39;d re-enter _to_sql.</span>
</span><span id="preprocess-599"><a href="#preprocess-599"><span class="linenos">599</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
</span><span id="preprocess-600"><a href="#preprocess-600"><span class="linenos">600</span></a> <span class="sa">f</span><span class="s2">&quot;Expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> requires a _sql method in order to be transformed.&quot;</span>
</span><span id="preprocess-601"><a href="#preprocess-601"><span class="linenos">601</span></a> <span class="p">)</span>
</span><span id="preprocess-602"><a href="#preprocess-602"><span class="linenos">602</span></a>
</span><span id="preprocess-603"><a href="#preprocess-603"><span class="linenos">603</span></a> <span class="k">return</span> <span class="n">transforms_handler</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-604"><a href="#preprocess-604"><span class="linenos">604</span></a>
</span><span id="preprocess-605"><a href="#preprocess-605"><span class="linenos">605</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</span><span id="preprocess-606"><a href="#preprocess-606"><span class="linenos">606</span></a>
</span><span id="preprocess-607"><a href="#preprocess-607"><span class="linenos">607</span></a> <span class="k">return</span> <span class="n">_to_sql</span>
<div class="pdoc-code codehilite"><pre><span></span><span id="preprocess-580"><a href="#preprocess-580"><span class="linenos">580</span></a><span class="k">def</span> <span class="nf">preprocess</span><span class="p">(</span>
</span><span id="preprocess-581"><a href="#preprocess-581"><span class="linenos">581</span></a> <span class="n">transforms</span><span class="p">:</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">Callable</span><span class="p">[[</span><span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">]],</span>
</span><span id="preprocess-582"><a href="#preprocess-582"><span class="linenos">582</span></a><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">t</span><span class="o">.</span><span class="n">Callable</span><span class="p">[[</span><span class="n">Generator</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">],</span> <span class="nb">str</span><span class="p">]:</span>
</span><span id="preprocess-583"><a href="#preprocess-583"><span class="linenos">583</span></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
</span><span id="preprocess-584"><a href="#preprocess-584"><span class="linenos">584</span></a><span class="sd"> Creates a new transform by chaining a sequence of transformations and converts the resulting</span>
</span><span id="preprocess-585"><a href="#preprocess-585"><span class="linenos">585</span></a><span class="sd"> expression to SQL, using either the &quot;_sql&quot; method corresponding to the resulting expression,</span>
</span><span id="preprocess-586"><a href="#preprocess-586"><span class="linenos">586</span></a><span class="sd"> or the appropriate `Generator.TRANSFORMS` function (when applicable -- see below).</span>
</span><span id="preprocess-587"><a href="#preprocess-587"><span class="linenos">587</span></a>
</span><span id="preprocess-588"><a href="#preprocess-588"><span class="linenos">588</span></a><span class="sd"> Args:</span>
</span><span id="preprocess-589"><a href="#preprocess-589"><span class="linenos">589</span></a><span class="sd"> transforms: sequence of transform functions. These will be called in order.</span>
</span><span id="preprocess-590"><a href="#preprocess-590"><span class="linenos">590</span></a>
</span><span id="preprocess-591"><a href="#preprocess-591"><span class="linenos">591</span></a><span class="sd"> Returns:</span>
</span><span id="preprocess-592"><a href="#preprocess-592"><span class="linenos">592</span></a><span class="sd"> Function that can be used as a generator transform.</span>
</span><span id="preprocess-593"><a href="#preprocess-593"><span class="linenos">593</span></a><span class="sd"> &quot;&quot;&quot;</span>
</span><span id="preprocess-594"><a href="#preprocess-594"><span class="linenos">594</span></a>
</span><span id="preprocess-595"><a href="#preprocess-595"><span class="linenos">595</span></a> <span class="k">def</span> <span class="nf">_to_sql</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">:</span> <span class="n">exp</span><span class="o">.</span><span class="n">Expression</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span><span id="preprocess-596"><a href="#preprocess-596"><span class="linenos">596</span></a> <span class="n">expression_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-597"><a href="#preprocess-597"><span class="linenos">597</span></a>
</span><span id="preprocess-598"><a href="#preprocess-598"><span class="linenos">598</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">0</span><span class="p">](</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-599"><a href="#preprocess-599"><span class="linenos">599</span></a> <span class="k">for</span> <span class="n">transform</span> <span class="ow">in</span> <span class="n">transforms</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span><span id="preprocess-600"><a href="#preprocess-600"><span class="linenos">600</span></a> <span class="n">expression</span> <span class="o">=</span> <span class="n">transform</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-601"><a href="#preprocess-601"><span class="linenos">601</span></a>
</span><span id="preprocess-602"><a href="#preprocess-602"><span class="linenos">602</span></a> <span class="n">_sql_handler</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="o">.</span><span class="n">key</span> <span class="o">+</span> <span class="s2">&quot;_sql&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
</span><span id="preprocess-603"><a href="#preprocess-603"><span class="linenos">603</span></a> <span class="k">if</span> <span class="n">_sql_handler</span><span class="p">:</span>
</span><span id="preprocess-604"><a href="#preprocess-604"><span class="linenos">604</span></a> <span class="k">return</span> <span class="n">_sql_handler</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-605"><a href="#preprocess-605"><span class="linenos">605</span></a>
</span><span id="preprocess-606"><a href="#preprocess-606"><span class="linenos">606</span></a> <span class="n">transforms_handler</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">TRANSFORMS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">))</span>
</span><span id="preprocess-607"><a href="#preprocess-607"><span class="linenos">607</span></a> <span class="k">if</span> <span class="n">transforms_handler</span><span class="p">:</span>
</span><span id="preprocess-608"><a href="#preprocess-608"><span class="linenos">608</span></a> <span class="k">if</span> <span class="n">expression_type</span> <span class="ow">is</span> <span class="nb">type</span><span class="p">(</span><span class="n">expression</span><span class="p">):</span>
</span><span id="preprocess-609"><a href="#preprocess-609"><span class="linenos">609</span></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">expression</span><span class="p">,</span> <span class="n">exp</span><span class="o">.</span><span class="n">Func</span><span class="p">):</span>
</span><span id="preprocess-610"><a href="#preprocess-610"><span class="linenos">610</span></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">function_fallback_sql</span><span class="p">(</span><span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-611"><a href="#preprocess-611"><span class="linenos">611</span></a>
</span><span id="preprocess-612"><a href="#preprocess-612"><span class="linenos">612</span></a> <span class="c1"># Ensures we don&#39;t enter an infinite loop. This can happen when the original expression</span>
</span><span id="preprocess-613"><a href="#preprocess-613"><span class="linenos">613</span></a> <span class="c1"># has the same type as the final expression and there&#39;s no _sql method available for it,</span>
</span><span id="preprocess-614"><a href="#preprocess-614"><span class="linenos">614</span></a> <span class="c1"># because then it&#39;d re-enter _to_sql.</span>
</span><span id="preprocess-615"><a href="#preprocess-615"><span class="linenos">615</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
</span><span id="preprocess-616"><a href="#preprocess-616"><span class="linenos">616</span></a> <span class="sa">f</span><span class="s2">&quot;Expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> requires a _sql method in order to be transformed.&quot;</span>
</span><span id="preprocess-617"><a href="#preprocess-617"><span class="linenos">617</span></a> <span class="p">)</span>
</span><span id="preprocess-618"><a href="#preprocess-618"><span class="linenos">618</span></a>
</span><span id="preprocess-619"><a href="#preprocess-619"><span class="linenos">619</span></a> <span class="k">return</span> <span class="n">transforms_handler</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">)</span>
</span><span id="preprocess-620"><a href="#preprocess-620"><span class="linenos">620</span></a>
</span><span id="preprocess-621"><a href="#preprocess-621"><span class="linenos">621</span></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported expression type </span><span class="si">{</span><span class="n">expression</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</span><span id="preprocess-622"><a href="#preprocess-622"><span class="linenos">622</span></a>
</span><span id="preprocess-623"><a href="#preprocess-623"><span class="linenos">623</span></a> <span class="k">return</span> <span class="n">_to_sql</span>
</span></pre></div>

View file

@ -88,13 +88,11 @@ def parse(
@t.overload
def parse_one(sql: str, *, into: t.Type[E], **opts) -> E:
...
def parse_one(sql: str, *, into: t.Type[E], **opts) -> E: ...
@t.overload
def parse_one(sql: str, **opts) -> Expression:
...
def parse_one(sql: str, **opts) -> Expression: ...
def parse_one(

View file

@ -140,12 +140,10 @@ class DataFrame:
return cte, name
@t.overload
def _ensure_list_of_columns(self, cols: t.Collection[ColumnOrLiteral]) -> t.List[Column]:
...
def _ensure_list_of_columns(self, cols: t.Collection[ColumnOrLiteral]) -> t.List[Column]: ...
@t.overload
def _ensure_list_of_columns(self, cols: ColumnOrLiteral) -> t.List[Column]:
...
def _ensure_list_of_columns(self, cols: ColumnOrLiteral) -> t.List[Column]: ...
def _ensure_list_of_columns(self, cols):
return Column.ensure_cols(ensure_list(cols))

View file

@ -210,7 +210,7 @@ def sec(col: ColumnOrName) -> Column:
def signum(col: ColumnOrName) -> Column:
return Column.invoke_anonymous_function(col, "SIGNUM")
return Column.invoke_expression_over_column(col, expression.Sign)
def sin(col: ColumnOrName) -> Column:
@ -592,7 +592,7 @@ def date_diff(end: ColumnOrName, start: ColumnOrName) -> Column:
def add_months(start: ColumnOrName, months: t.Union[ColumnOrName, int]) -> Column:
return Column.invoke_anonymous_function(start, "ADD_MONTHS", months)
return Column.invoke_expression_over_column(start, expression.AddMonths, expression=months)
def months_between(

View file

@ -42,7 +42,10 @@ def _derived_table_values_to_unnest(self: BigQuery.Generator, expression: exp.Va
alias = expression.args.get("alias")
for tup in expression.find_all(exp.Tuple):
field_aliases = alias.columns if alias else (f"_c{i}" for i in range(len(tup.expressions)))
expressions = [exp.alias_(fld, name) for fld, name in zip(tup.expressions, field_aliases)]
expressions = [
exp.PropertyEQ(this=exp.to_identifier(name), expression=fld)
for name, fld in zip(field_aliases, tup.expressions)
]
structs.append(exp.Struct(expressions=expressions))
return self.unnest_sql(exp.Unnest(expressions=[exp.array(*structs, copy=False)]))
@ -111,6 +114,8 @@ def _alias_ordered_group(expression: exp.Expression) -> exp.Expression:
}
for grouped in group.expressions:
if grouped.is_int:
continue
alias = aliases.get(grouped)
if alias:
grouped.replace(exp.column(alias))
@ -226,8 +231,11 @@ class BigQuery(Dialect):
# bigquery udfs are case sensitive
NORMALIZE_FUNCTIONS = False
# https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_elements_date_time
TIME_MAPPING = {
"%D": "%m/%d/%y",
"%E*S": "%S.%f",
"%E6S": "%S.%f",
}
ESCAPE_SEQUENCES = {
@ -266,14 +274,20 @@ class BigQuery(Dialect):
while isinstance(parent, exp.Dot):
parent = parent.parent
# In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least).
# The following check is essentially a heuristic to detect tables based on whether or
# not they're qualified. It also avoids normalizing UDFs, because they're case-sensitive.
if (
not isinstance(parent, exp.UserDefinedFunction)
and not (isinstance(parent, exp.Table) and parent.db)
and not expression.meta.get("is_table")
):
# In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive
# by default. The following check uses a heuristic to detect tables based on whether
# they are qualified. This should generally be correct, because tables in BigQuery
# must be qualified with at least a dataset, unless @@dataset_id is set.
case_sensitive = (
isinstance(parent, exp.UserDefinedFunction)
or (
isinstance(parent, exp.Table)
and parent.db
and (parent.meta.get("quoted_table") or not parent.meta.get("maybe_column"))
)
or expression.meta.get("is_table")
)
if not case_sensitive:
expression.set("this", expression.this.lower())
return expression
@ -302,6 +316,7 @@ class BigQuery(Dialect):
"BYTES": TokenType.BINARY,
"CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
"DECLARE": TokenType.COMMAND,
"ELSEIF": TokenType.COMMAND,
"EXCEPTION": TokenType.COMMAND,
"FLOAT64": TokenType.DOUBLE,
"FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
@ -315,8 +330,8 @@ class BigQuery(Dialect):
class Parser(parser.Parser):
PREFIXED_PIVOT_COLUMNS = True
LOG_DEFAULTS_TO_LN = True
SUPPORTS_IMPLICIT_UNNEST = True
FUNCTIONS = {
**parser.Parser.FUNCTIONS,
@ -410,6 +425,7 @@ class BigQuery(Dialect):
STATEMENT_PARSERS = {
**parser.Parser.STATEMENT_PARSERS,
TokenType.ELSE: lambda self: self._parse_as_command(self._prev),
TokenType.END: lambda self: self._parse_as_command(self._prev),
TokenType.FOR: lambda self: self._parse_for_in(),
}
@ -433,8 +449,11 @@ class BigQuery(Dialect):
if isinstance(this, exp.Identifier):
table_name = this.name
while self._match(TokenType.DASH, advance=False) and self._next:
self._advance(2)
table_name += f"-{self._prev.text}"
text = ""
while self._curr and self._curr.token_type != TokenType.DOT:
self._advance()
text += self._prev.text
table_name += text
this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
elif isinstance(this, exp.Literal):
@ -448,12 +467,28 @@ class BigQuery(Dialect):
return this
def _parse_table_parts(
self, schema: bool = False, is_db_reference: bool = False
self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
) -> exp.Table:
table = super()._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
table = super()._parse_table_parts(
schema=schema, is_db_reference=is_db_reference, wildcard=True
)
# proj-1.db.tbl -- `1.` is tokenized as a float so we need to unravel it here
if not table.catalog:
if table.db:
parts = table.db.split(".")
if len(parts) == 2 and not table.args["db"].quoted:
table.set("catalog", exp.Identifier(this=parts[0]))
table.set("db", exp.Identifier(this=parts[1]))
else:
parts = table.name.split(".")
if len(parts) == 2 and not table.this.quoted:
table.set("db", exp.Identifier(this=parts[0]))
table.set("this", exp.Identifier(this=parts[1]))
if isinstance(table.this, exp.Identifier) and "." in table.name:
catalog, db, this, *rest = (
t.cast(t.Optional[exp.Expression], exp.to_identifier(x))
t.cast(t.Optional[exp.Expression], exp.to_identifier(x, quoted=True))
for x in split_num_words(table.name, ".", 3)
)
@ -461,16 +496,15 @@ class BigQuery(Dialect):
this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
table = exp.Table(this=this, db=db, catalog=catalog)
table.meta["quoted_table"] = True
return table
@t.overload
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject:
...
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
@t.overload
def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg:
...
def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
def _parse_json_object(self, agg=False):
json_object = super()._parse_json_object()
@ -532,6 +566,7 @@ class BigQuery(Dialect):
IGNORE_NULLS_IN_FUNC = True
JSON_PATH_SINGLE_QUOTE_ESCAPE = True
CAN_IMPLEMENT_ARRAY_ANY = True
NAMED_PLACEHOLDER_TOKEN = "@"
TRANSFORMS = {
**generator.Generator.TRANSFORMS,
@ -762,22 +797,25 @@ class BigQuery(Dialect):
"within",
}
def table_parts(self, expression: exp.Table) -> str:
# Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so
# we need to make sure the correct quoting is used in each case.
#
# For example, if there is a CTE x that clashes with a schema name, then the former will
# return the table y in that schema, whereas the latter will return the CTE's y column:
#
# - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y` -> cross join
# - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest
if expression.meta.get("quoted_table"):
table_parts = ".".join(p.name for p in expression.parts)
return self.sql(exp.Identifier(this=table_parts, quoted=True))
return super().table_parts(expression)
def timetostr_sql(self, expression: exp.TimeToStr) -> str:
this = expression.this if isinstance(expression.this, exp.TsOrDsToDate) else expression
return self.func("FORMAT_DATE", self.format_time(expression), this.this)
def struct_sql(self, expression: exp.Struct) -> str:
args = []
for expr in expression.expressions:
if isinstance(expr, self.KEY_VALUE_DEFINITIONS):
arg = f"{self.sql(expr, 'expression')} AS {expr.this.name}"
else:
arg = self.sql(expr)
args.append(arg)
return self.func("STRUCT", *args)
def eq_sql(self, expression: exp.EQ) -> str:
# Operands of = cannot be NULL in BigQuery
if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null):
@ -803,7 +841,7 @@ class BigQuery(Dialect):
def array_sql(self, expression: exp.Array) -> str:
first_arg = seq_get(expression.expressions, 0)
if isinstance(first_arg, exp.Subqueryable):
if isinstance(first_arg, exp.Query):
return f"ARRAY{self.wrap(self.sql(first_arg))}"
return inline_array_sql(self, expression)

View file

@ -68,7 +68,6 @@ class ClickHouse(Dialect):
"DATE32": TokenType.DATE32,
"DATETIME64": TokenType.DATETIME64,
"DICTIONARY": TokenType.DICTIONARY,
"ENUM": TokenType.ENUM,
"ENUM8": TokenType.ENUM8,
"ENUM16": TokenType.ENUM16,
"FINAL": TokenType.FINAL,
@ -93,6 +92,7 @@ class ClickHouse(Dialect):
"AGGREGATEFUNCTION": TokenType.AGGREGATEFUNCTION,
"SIMPLEAGGREGATEFUNCTION": TokenType.SIMPLEAGGREGATEFUNCTION,
"SYSTEM": TokenType.COMMAND,
"PREWHERE": TokenType.PREWHERE,
}
SINGLE_TOKENS = {
@ -129,6 +129,7 @@ class ClickHouse(Dialect):
"MAP": parser.build_var_map,
"MATCH": exp.RegexpLike.from_arg_list,
"RANDCANONICAL": exp.Rand.from_arg_list,
"TUPLE": exp.Struct.from_arg_list,
"UNIQ": exp.ApproxDistinct.from_arg_list,
"XOR": lambda args: exp.Xor(expressions=args),
}
@ -390,7 +391,7 @@ class ClickHouse(Dialect):
return self.expression(
exp.CTE,
this=self._parse_field(),
this=self._parse_conjunction(),
alias=self._parse_table_alias(),
scalar=True,
)
@ -732,3 +733,7 @@ class ClickHouse(Dialect):
return f"{this_name}{self.sep()}{this_properties}{self.sep()}{this_schema}"
return super().createable_sql(expression, locations)
def prewhere_sql(self, expression: exp.PreWhere) -> str:
this = self.indent(self.sql(expression, "this"))
return f"{self.seg('PREWHERE')}{self.sep()}{this}"

View file

@ -69,7 +69,7 @@ class Databricks(Spark):
def columndef_sql(self, expression: exp.ColumnDef, sep: str = " ") -> str:
constraint = expression.find(exp.GeneratedAsIdentityColumnConstraint)
kind = expression.args.get("kind")
kind = expression.kind
if (
constraint
and isinstance(kind, exp.DataType)

View file

@ -443,7 +443,7 @@ class Dialect(metaclass=_Dialect):
identify: If set to `False`, the quotes will only be added if the identifier is deemed
"unsafe", with respect to its characters and this dialect's normalization strategy.
"""
if isinstance(expression, exp.Identifier):
if isinstance(expression, exp.Identifier) and not isinstance(expression.parent, exp.Func):
name = expression.this
expression.set(
"quoted",

View file

@ -21,6 +21,7 @@ class Doris(MySQL):
**MySQL.Parser.FUNCTIONS,
"COLLECT_SET": exp.ArrayUniqueAgg.from_arg_list,
"DATE_TRUNC": build_timestamp_trunc,
"MONTHS_ADD": exp.AddMonths.from_arg_list,
"REGEXP": exp.RegexpLike.from_arg_list,
"TO_DATE": exp.TsOrDsToDate.from_arg_list,
}
@ -41,6 +42,7 @@ class Doris(MySQL):
TRANSFORMS = {
**MySQL.Generator.TRANSFORMS,
exp.AddMonths: rename_func("MONTHS_ADD"),
exp.ApproxDistinct: approx_count_distinct_sql,
exp.ArgMax: rename_func("MAX_BY"),
exp.ArgMin: rename_func("MIN_BY"),
@ -58,7 +60,6 @@ class Doris(MySQL):
exp.StrToUnix: lambda self, e: self.func("UNIX_TIMESTAMP", e.this, self.format_time(e)),
exp.Split: rename_func("SPLIT_BY_STRING"),
exp.TimeStrToDate: rename_func("TO_DATE"),
exp.ToChar: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)),
exp.TsOrDsAdd: lambda self, e: self.func("DATE_ADD", e.this, e.expression),
exp.TsOrDsToDate: lambda self, e: self.func("TO_DATE", e.this),
exp.TimeToUnix: rename_func("UNIX_TIMESTAMP"),

View file

@ -156,6 +156,3 @@ class Drill(Dialect):
exp.TsOrDiToDi: lambda self,
e: f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS VARCHAR), '-', ''), 1, 8) AS INT)",
}
def normalize_func(self, name: str) -> str:
return name if exp.SAFE_IDENTIFIER_RE.match(name) else f"`{name}`"

View file

@ -79,6 +79,21 @@ def _build_date_diff(args: t.List) -> exp.Expression:
return exp.DateDiff(this=seq_get(args, 2), expression=seq_get(args, 1), unit=seq_get(args, 0))
def _build_generate_series(end_exclusive: bool = False) -> t.Callable[[t.List], exp.GenerateSeries]:
def _builder(args: t.List) -> exp.GenerateSeries:
# Check https://duckdb.org/docs/sql/functions/nested.html#range-functions
if len(args) == 1:
# DuckDB uses 0 as a default for the series' start when it's omitted
args.insert(0, exp.Literal.number("0"))
gen_series = exp.GenerateSeries.from_arg_list(args)
gen_series.set("is_end_exclusive", end_exclusive)
return gen_series
return _builder
def _build_make_timestamp(args: t.List) -> exp.Expression:
if len(args) == 1:
return exp.UnixToTime(this=seq_get(args, 0), scale=exp.UnixToTime.MICROS)
@ -95,13 +110,13 @@ def _build_make_timestamp(args: t.List) -> exp.Expression:
def _struct_sql(self: DuckDB.Generator, expression: exp.Struct) -> str:
args: t.List[str] = []
for expr in expression.expressions:
if isinstance(expr, exp.Alias):
key = expr.alias
value = expr.this
else:
key = expr.name or expr.this.name
for i, expr in enumerate(expression.expressions):
if isinstance(expr, exp.PropertyEQ):
key = expr.name
value = expr.expression
else:
key = f"_{i}"
value = expr
args.append(f"{self.sql(exp.Literal.string(key))}: {self.sql(value)}")
@ -148,13 +163,6 @@ def _rename_unless_within_group(
)
def _build_struct_pack(args: t.List) -> exp.Struct:
args_with_columns_as_identifiers = [
exp.PropertyEQ(this=arg.this.this, expression=arg.expression) for arg in args
]
return exp.Struct.from_arg_list(args_with_columns_as_identifiers)
class DuckDB(Dialect):
NULL_ORDERING = "nulls_are_last"
SUPPORTS_USER_DEFINED_TYPES = False
@ -189,6 +197,7 @@ class DuckDB(Dialect):
"CHARACTER VARYING": TokenType.TEXT,
"EXCLUDE": TokenType.EXCEPT,
"LOGICAL": TokenType.BOOLEAN,
"ONLY": TokenType.ONLY,
"PIVOT_WIDER": TokenType.PIVOT,
"SIGNED": TokenType.INT,
"STRING": TokenType.VARCHAR,
@ -213,6 +222,8 @@ class DuckDB(Dialect):
TokenType.TILDA: exp.RegexpLike,
}
FUNCTIONS_WITH_ALIASED_ARGS = {*parser.Parser.FUNCTIONS_WITH_ALIASED_ARGS, "STRUCT_PACK"}
FUNCTIONS = {
**parser.Parser.FUNCTIONS,
"ARRAY_HAS": exp.ArrayContains.from_arg_list,
@ -261,12 +272,14 @@ class DuckDB(Dialect):
"STRING_SPLIT_REGEX": exp.RegexpSplit.from_arg_list,
"STRING_TO_ARRAY": exp.Split.from_arg_list,
"STRPTIME": build_formatted_time(exp.StrToTime, "duckdb"),
"STRUCT_PACK": _build_struct_pack,
"STRUCT_PACK": exp.Struct.from_arg_list,
"STR_SPLIT": exp.Split.from_arg_list,
"STR_SPLIT_REGEX": exp.RegexpSplit.from_arg_list,
"TO_TIMESTAMP": exp.UnixToTime.from_arg_list,
"UNNEST": exp.Explode.from_arg_list,
"XOR": binary_from_function(exp.BitwiseXor),
"GENERATE_SERIES": _build_generate_series(),
"RANGE": _build_generate_series(end_exclusive=True),
}
FUNCTION_PARSERS = parser.Parser.FUNCTION_PARSERS.copy()
@ -313,6 +326,8 @@ class DuckDB(Dialect):
return pivot_column_names(aggregations, dialect="duckdb")
class Generator(generator.Generator):
PARAMETER_TOKEN = "$"
NAMED_PLACEHOLDER_TOKEN = "$"
JOIN_HINTS = False
TABLE_HINTS = False
QUERY_HINTS = False
@ -535,5 +550,22 @@ class DuckDB(Dialect):
return self.sql(expression, "this")
return super().columndef_sql(expression, sep)
def placeholder_sql(self, expression: exp.Placeholder) -> str:
return f"${expression.name}" if expression.name else "?"
def join_sql(self, expression: exp.Join) -> str:
if (
expression.side == "LEFT"
and not expression.args.get("on")
and isinstance(expression.this, exp.Unnest)
):
# Some dialects support `LEFT JOIN UNNEST(...)` without an explicit ON clause
# DuckDB doesn't, but we can just add a dummy ON clause that is always true
return super().join_sql(expression.on(exp.true()))
return super().join_sql(expression)
def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
# GENERATE_SERIES(a, b) -> [a, b], RANGE(a, b) -> [a, b)
if expression.args.get("is_end_exclusive"):
expression.set("is_end_exclusive", None)
return rename_func("RANGE")(self, expression)
return super().generateseries_sql(expression)

View file

@ -140,6 +140,15 @@ def _str_to_unix_sql(self: Hive.Generator, expression: exp.StrToUnix) -> str:
return self.func("UNIX_TIMESTAMP", expression.this, time_format("hive")(self, expression))
def _unix_to_time_sql(self: Hive.Generator, expression: exp.UnixToTime) -> str:
timestamp = self.sql(expression, "this")
scale = expression.args.get("scale")
if scale in (None, exp.UnixToTime.SECONDS):
return rename_func("FROM_UNIXTIME")(self, expression)
return f"FROM_UNIXTIME({timestamp} / POW(10, {scale}))"
def _str_to_date_sql(self: Hive.Generator, expression: exp.StrToDate) -> str:
this = self.sql(expression, "this")
time_format = self.format_time(expression)
@ -536,7 +545,7 @@ class Hive(Dialect):
exp.UnixToStr: lambda self, e: self.func(
"FROM_UNIXTIME", e.this, time_format("hive")(self, e)
),
exp.UnixToTime: rename_func("FROM_UNIXTIME"),
exp.UnixToTime: _unix_to_time_sql,
exp.UnixToTimeStr: rename_func("FROM_UNIXTIME"),
exp.PartitionedByProperty: lambda self, e: f"PARTITIONED BY {self.sql(e, 'this')}",
exp.SerdeProperties: lambda self, e: self.properties(e, prefix="WITH SERDEPROPERTIES"),
@ -609,9 +618,8 @@ class Hive(Dialect):
return self.properties(properties, prefix=self.seg("TBLPROPERTIES"))
def datatype_sql(self, expression: exp.DataType) -> str:
if (
expression.this in (exp.DataType.Type.VARCHAR, exp.DataType.Type.NVARCHAR)
and not expression.expressions
if expression.this in self.PARAMETERIZABLE_TEXT_TYPES and (
not expression.expressions or expression.expressions[0].name == "MAX"
):
expression = exp.DataType.build("text")
elif expression.is_type(exp.DataType.Type.TEXT) and expression.expressions:
@ -631,3 +639,15 @@ class Hive(Dialect):
def version_sql(self, expression: exp.Version) -> str:
sql = super().version_sql(expression)
return sql.replace("FOR ", "", 1)
def struct_sql(self, expression: exp.Struct) -> str:
values = []
for i, e in enumerate(expression.expressions):
if isinstance(e, exp.PropertyEQ):
self.unsupported("Hive does not support named structs.")
values.append(e.expression)
else:
values.append(e)
return self.func("STRUCT", *values)

View file

@ -185,7 +185,6 @@ class MySQL(Dialect):
KEYWORDS = {
**tokens.Tokenizer.KEYWORDS,
"CHARSET": TokenType.CHARACTER_SET,
"ENUM": TokenType.ENUM,
"FORCE": TokenType.FORCE,
"IGNORE": TokenType.IGNORE,
"LOCK TABLES": TokenType.COMMAND,
@ -391,6 +390,11 @@ class MySQL(Dialect):
"WARNINGS": _show_parser("WARNINGS"),
}
PROPERTY_PARSERS = {
**parser.Parser.PROPERTY_PARSERS,
"LOCK": lambda self: self._parse_property_assignment(exp.LockProperty),
}
SET_PARSERS = {
**parser.Parser.SET_PARSERS,
"PERSIST": lambda self: self._parse_set_item_assignment("PERSIST"),
@ -416,16 +420,11 @@ class MySQL(Dialect):
"SPATIAL",
}
PROFILE_TYPES = {
"ALL",
"BLOCK IO",
"CONTEXT SWITCHES",
"CPU",
"IPC",
"MEMORY",
"PAGE FAULTS",
"SOURCE",
"SWAPS",
PROFILE_TYPES: parser.OPTIONS_TYPE = {
**dict.fromkeys(("ALL", "CPU", "IPC", "MEMORY", "SOURCE", "SWAPS"), tuple()),
"BLOCK": ("IO",),
"CONTEXT": ("SWITCHES",),
"PAGE": ("FAULTS",),
}
TYPE_TOKENS = {

View file

@ -66,6 +66,26 @@ class Oracle(Dialect):
"FF6": "%f", # only 6 digits are supported in python formats
}
class Tokenizer(tokens.Tokenizer):
VAR_SINGLE_TOKENS = {"@", "$", "#"}
KEYWORDS = {
**tokens.Tokenizer.KEYWORDS,
"(+)": TokenType.JOIN_MARKER,
"BINARY_DOUBLE": TokenType.DOUBLE,
"BINARY_FLOAT": TokenType.FLOAT,
"COLUMNS": TokenType.COLUMN,
"MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE,
"MINUS": TokenType.EXCEPT,
"NVARCHAR2": TokenType.NVARCHAR,
"ORDER SIBLINGS BY": TokenType.ORDER_SIBLINGS_BY,
"SAMPLE": TokenType.TABLE_SAMPLE,
"START": TokenType.BEGIN,
"SYSDATE": TokenType.CURRENT_TIMESTAMP,
"TOP": TokenType.TOP,
"VARCHAR2": TokenType.VARCHAR,
}
class Parser(parser.Parser):
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER, TokenType.KEEP}
@ -93,6 +113,21 @@ class Oracle(Dialect):
"XMLTABLE": lambda self: self._parse_xml_table(),
}
NO_PAREN_FUNCTION_PARSERS = {
**parser.Parser.NO_PAREN_FUNCTION_PARSERS,
"CONNECT_BY_ROOT": lambda self: self.expression(
exp.ConnectByRoot, this=self._parse_column()
),
}
PROPERTY_PARSERS = {
**parser.Parser.PROPERTY_PARSERS,
"GLOBAL": lambda self: self._match_text_seq("TEMPORARY")
and self.expression(exp.TemporaryProperty, this="GLOBAL"),
"PRIVATE": lambda self: self._match_text_seq("TEMPORARY")
and self.expression(exp.TemporaryProperty, this="PRIVATE"),
}
QUERY_MODIFIER_PARSERS = {
**parser.Parser.QUERY_MODIFIER_PARSERS,
TokenType.ORDER_SIBLINGS_BY: lambda self: ("order", self._parse_order()),
@ -190,6 +225,7 @@ class Oracle(Dialect):
TRANSFORMS = {
**generator.Generator.TRANSFORMS,
exp.ConnectByRoot: lambda self, e: f"CONNECT_BY_ROOT {self.sql(e, 'this')}",
exp.DateStrToDate: lambda self, e: self.func(
"TO_DATE", e.this, exp.Literal.string("YYYY-MM-DD")
),
@ -207,6 +243,7 @@ class Oracle(Dialect):
exp.Substring: rename_func("SUBSTR"),
exp.Table: lambda self, e: self.table_sql(e, sep=" "),
exp.TableSample: lambda self, e: self.tablesample_sql(e, sep=" "),
exp.TemporaryProperty: lambda _, e: f"{e.name or 'GLOBAL'} TEMPORARY",
exp.TimeToStr: lambda self, e: self.func("TO_CHAR", e.this, self.format_time(e)),
exp.ToChar: lambda self, e: self.function_fallback_sql(e),
exp.Trim: trim_sql,
@ -242,23 +279,3 @@ class Oracle(Dialect):
if len(expression.args.get("actions", [])) > 1:
return f"ADD ({actions})"
return f"ADD {actions}"
class Tokenizer(tokens.Tokenizer):
VAR_SINGLE_TOKENS = {"@", "$", "#"}
KEYWORDS = {
**tokens.Tokenizer.KEYWORDS,
"(+)": TokenType.JOIN_MARKER,
"BINARY_DOUBLE": TokenType.DOUBLE,
"BINARY_FLOAT": TokenType.FLOAT,
"COLUMNS": TokenType.COLUMN,
"MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE,
"MINUS": TokenType.EXCEPT,
"NVARCHAR2": TokenType.NVARCHAR,
"ORDER SIBLINGS BY": TokenType.ORDER_SIBLINGS_BY,
"SAMPLE": TokenType.TABLE_SAMPLE,
"START": TokenType.BEGIN,
"SYSDATE": TokenType.CURRENT_TIMESTAMP,
"TOP": TokenType.TOP,
"VARCHAR2": TokenType.VARCHAR,
}

View file

@ -138,7 +138,9 @@ def _auto_increment_to_serial(expression: exp.Expression) -> exp.Expression:
def _serial_to_generated(expression: exp.Expression) -> exp.Expression:
kind = expression.args.get("kind")
if not isinstance(expression, exp.ColumnDef):
return expression
kind = expression.kind
if not kind:
return expression
@ -279,6 +281,7 @@ class Postgres(Dialect):
"TEMP": TokenType.TEMPORARY,
"CSTRING": TokenType.PSEUDO_TYPE,
"OID": TokenType.OBJECT_IDENTIFIER,
"ONLY": TokenType.ONLY,
"OPERATOR": TokenType.OPERATOR,
"REGCLASS": TokenType.OBJECT_IDENTIFIER,
"REGCOLLATION": TokenType.OBJECT_IDENTIFIER,
@ -451,6 +454,7 @@ class Postgres(Dialect):
exp.JSONBExtract: lambda self, e: self.binary(e, "#>"),
exp.JSONBExtractScalar: lambda self, e: self.binary(e, "#>>"),
exp.JSONBContains: lambda self, e: self.binary(e, "?"),
exp.ParseJSON: lambda self, e: self.sql(exp.cast(e.this, exp.DataType.Type.JSON)),
exp.JSONPathKey: json_path_key_only_name,
exp.JSONPathRoot: lambda *_: "",
exp.JSONPathSubscript: lambda self, e: self.json_path_part(e.this),
@ -506,6 +510,26 @@ class Postgres(Dialect):
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
}
def unnest_sql(self, expression: exp.Unnest) -> str:
if len(expression.expressions) == 1:
from sqlglot.optimizer.annotate_types import annotate_types
this = annotate_types(expression.expressions[0])
if this.is_type("array<json>"):
while isinstance(this, exp.Cast):
this = this.this
arg = self.sql(exp.cast(this, exp.DataType.Type.JSON))
alias = self.sql(expression, "alias")
alias = f" AS {alias}" if alias else ""
if expression.args.get("offset"):
self.unsupported("Unsupported JSON_ARRAY_ELEMENTS with offset")
return f"JSON_ARRAY_ELEMENTS({arg}){alias}"
return super().unnest_sql(expression)
def bracket_sql(self, expression: exp.Bracket) -> str:
"""Forms like ARRAY[1, 2, 3][3] aren't allowed; we need to wrap the ARRAY."""
if isinstance(expression.this, exp.Array):

View file

@ -453,11 +453,32 @@ class Presto(Dialect):
return super().bracket_sql(expression)
def struct_sql(self, expression: exp.Struct) -> str:
if any(isinstance(arg, self.KEY_VALUE_DEFINITIONS) for arg in expression.expressions):
self.unsupported("Struct with key-value definitions is unsupported.")
return self.function_fallback_sql(expression)
from sqlglot.optimizer.annotate_types import annotate_types
return rename_func("ROW")(self, expression)
expression = annotate_types(expression)
values: t.List[str] = []
schema: t.List[str] = []
unknown_type = False
for e in expression.expressions:
if isinstance(e, exp.PropertyEQ):
if e.type and e.type.is_type(exp.DataType.Type.UNKNOWN):
unknown_type = True
else:
schema.append(f"{self.sql(e, 'this')} {self.sql(e.type)}")
values.append(self.sql(e, "expression"))
else:
values.append(self.sql(e))
size = len(expression.expressions)
if not size or len(schema) != size:
if unknown_type:
self.unsupported(
"Cannot convert untyped key-value definitions (try annotate_types)."
)
return self.func("ROW", *values)
return f"CAST(ROW({', '.join(values)}) AS ROW({', '.join(schema)}))"
def interval_sql(self, expression: exp.Interval) -> str:
unit = self.sql(expression, "unit")

View file

@ -70,6 +70,8 @@ class Redshift(Postgres):
"SYSDATE": lambda self: self.expression(exp.CurrentTimestamp, transaction=True),
}
SUPPORTS_IMPLICIT_UNNEST = True
def _parse_table(
self,
schema: bool = False,
@ -124,27 +126,6 @@ class Redshift(Postgres):
self._retreat(index)
return None
def _parse_query_modifiers(
self, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]:
this = super()._parse_query_modifiers(this)
if this:
refs = set()
for i, join in enumerate(this.args.get("joins", [])):
refs.add(
(
this.args["from"] if i == 0 else this.args["joins"][i - 1]
).this.alias.lower()
)
table = join.this
if isinstance(table, exp.Table) and not join.args.get("on"):
if table.parts[0].name.lower() in refs:
table.replace(table.to_column())
return this
class Tokenizer(Postgres.Tokenizer):
BIT_STRINGS = []
HEX_STRINGS = []
@ -225,6 +206,18 @@ class Redshift(Postgres):
RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot", "type"}
def unnest_sql(self, expression: exp.Unnest) -> str:
args = expression.expressions
num_args = len(args)
if num_args > 1:
self.unsupported(f"Unsupported number of arguments in UNNEST: {num_args}")
return ""
arg = self.sql(seq_get(args, 0))
alias = self.expressions(expression.args.get("alias"), key="columns")
return f"{arg} AS {alias}" if alias else arg
def with_properties(self, properties: exp.Properties) -> str:
"""Redshift doesn't have `WITH` as part of their with_properties so we remove it"""
return self.properties(properties, prefix=" ", suffix="")

View file

@ -21,7 +21,7 @@ from sqlglot.dialects.dialect import (
var_map_sql,
)
from sqlglot.expressions import Literal
from sqlglot.helper import is_int, seq_get
from sqlglot.helper import flatten, is_int, seq_get
from sqlglot.tokens import TokenType
if t.TYPE_CHECKING:
@ -66,7 +66,7 @@ def _build_object_construct(args: t.List) -> t.Union[exp.StarMap, exp.Struct]:
return exp.Struct(
expressions=[
t.cast(exp.Condition, k).eq(v) for k, v in zip(expression.keys, expression.values)
exp.PropertyEQ(this=k, expression=v) for k, v in zip(expression.keys, expression.values)
]
)
@ -409,8 +409,16 @@ class Snowflake(Dialect):
"TERSE OBJECTS": _show_parser("OBJECTS"),
"TABLES": _show_parser("TABLES"),
"TERSE TABLES": _show_parser("TABLES"),
"VIEWS": _show_parser("VIEWS"),
"TERSE VIEWS": _show_parser("VIEWS"),
"PRIMARY KEYS": _show_parser("PRIMARY KEYS"),
"TERSE PRIMARY KEYS": _show_parser("PRIMARY KEYS"),
"IMPORTED KEYS": _show_parser("IMPORTED KEYS"),
"TERSE IMPORTED KEYS": _show_parser("IMPORTED KEYS"),
"UNIQUE KEYS": _show_parser("UNIQUE KEYS"),
"TERSE UNIQUE KEYS": _show_parser("UNIQUE KEYS"),
"SEQUENCES": _show_parser("SEQUENCES"),
"TERSE SEQUENCES": _show_parser("SEQUENCES"),
"COLUMNS": _show_parser("COLUMNS"),
"USERS": _show_parser("USERS"),
"TERSE USERS": _show_parser("USERS"),
@ -424,11 +432,13 @@ class Snowflake(Dialect):
FLATTEN_COLUMNS = ["SEQ", "KEY", "PATH", "INDEX", "VALUE", "THIS"]
SCHEMA_KINDS = {"OBJECTS", "TABLES", "VIEWS", "SEQUENCES", "UNIQUE KEYS", "IMPORTED KEYS"}
def _parse_colon_get_path(
self: parser.Parser, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]:
while True:
path = self._parse_bitwise()
path = self._parse_bitwise() or self._parse_var(any_token=True)
# The cast :: operator has a lower precedence than the extraction operator :, so
# we rearrange the AST appropriately to avoid casting the 2nd argument of GET_PATH
@ -535,7 +545,7 @@ class Snowflake(Dialect):
return table
def _parse_table_parts(
self, schema: bool = False, is_db_reference: bool = False
self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
) -> exp.Table:
# https://docs.snowflake.com/en/user-guide/querying-stage
if self._match(TokenType.STRING, advance=False):
@ -603,7 +613,7 @@ class Snowflake(Dialect):
if self._curr:
scope = self._parse_table_parts()
elif self._curr:
scope_kind = "SCHEMA" if this in ("OBJECTS", "TABLES") else "TABLE"
scope_kind = "SCHEMA" if this in self.SCHEMA_KINDS else "TABLE"
scope = self._parse_table_parts()
return self.expression(
@ -758,10 +768,6 @@ class Snowflake(Dialect):
"POSITION", e.args.get("substr"), e.this, e.args.get("position")
),
exp.StrToTime: lambda self, e: self.func("TO_TIMESTAMP", e.this, self.format_time(e)),
exp.Struct: lambda self, e: self.func(
"OBJECT_CONSTRUCT",
*(arg for expression in e.expressions for arg in expression.flatten()),
),
exp.Stuff: rename_func("INSERT"),
exp.TimestampDiff: lambda self, e: self.func(
"TIMESTAMPDIFF", e.unit, e.expression, e.this
@ -937,3 +943,19 @@ class Snowflake(Dialect):
def cluster_sql(self, expression: exp.Cluster) -> str:
return f"CLUSTER BY ({self.expressions(expression, flat=True)})"
def struct_sql(self, expression: exp.Struct) -> str:
keys = []
values = []
for i, e in enumerate(expression.expressions):
if isinstance(e, exp.PropertyEQ):
keys.append(
exp.Literal.string(e.name) if isinstance(e.this, exp.Identifier) else e.this
)
values.append(e.expression)
else:
keys.append(exp.Literal.string(f"_{i}"))
values.append(e)
return self.func("OBJECT_CONSTRUCT", *flatten(zip(keys, values)))

View file

@ -263,14 +263,9 @@ class Spark2(Hive):
CREATE_FUNCTION_RETURN_AS = False
def struct_sql(self, expression: exp.Struct) -> str:
args = []
for arg in expression.expressions:
if isinstance(arg, self.KEY_VALUE_DEFINITIONS):
args.append(exp.alias_(arg.expression, arg.this.name))
else:
args.append(arg)
from sqlglot.generator import Generator
return self.func("STRUCT", *args)
return Generator.struct_sql(self, expression)
def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
if is_parse_json(expression.this):

View file

@ -92,6 +92,7 @@ class SQLite(Dialect):
NVL2_SUPPORTED = False
JSON_PATH_BRACKETED_KEY_SUPPORTED = False
SUPPORTS_CREATE_TABLE_LIKE = False
SUPPORTS_TABLE_ALIAS_COLUMNS = False
SUPPORTED_JSON_PATH_PARTS = {
exp.JSONPathKey,
@ -173,6 +174,21 @@ class SQLite(Dialect):
return super().cast_sql(expression)
def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
parent = expression.parent
alias = parent and parent.args.get("alias")
if isinstance(alias, exp.TableAlias) and alias.columns:
column_alias = alias.columns[0]
alias.set("columns", None)
sql = self.sql(
exp.select(exp.alias_("value", column_alias)).from_(expression).subquery()
)
else:
sql = super().generateseries_sql(expression)
return sql
def datediff_sql(self, expression: exp.DateDiff) -> str:
unit = expression.args.get("unit")
unit = unit.name.upper() if unit else "DAY"

View file

@ -18,7 +18,6 @@ from sqlglot.dialects.dialect import (
timestrtotime_sql,
trim_sql,
)
from sqlglot.expressions import DataType
from sqlglot.helper import seq_get
from sqlglot.time import format_time
from sqlglot.tokens import TokenType
@ -63,6 +62,44 @@ DEFAULT_START_DATE = datetime.date(1900, 1, 1)
BIT_TYPES = {exp.EQ, exp.NEQ, exp.Is, exp.In, exp.Select, exp.Alias}
# Unsupported options:
# - OPTIMIZE FOR ( @variable_name { UNKNOWN | = <literal_constant> } [ , ...n ] )
# - TABLE HINT
OPTIONS: parser.OPTIONS_TYPE = {
**dict.fromkeys(
(
"DISABLE_OPTIMIZED_PLAN_FORCING",
"FAST",
"IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX",
"LABEL",
"MAXDOP",
"MAXRECURSION",
"MAX_GRANT_PERCENT",
"MIN_GRANT_PERCENT",
"NO_PERFORMANCE_SPOOL",
"QUERYTRACEON",
"RECOMPILE",
),
tuple(),
),
"CONCAT": ("UNION",),
"DISABLE": ("EXTERNALPUSHDOWN", "SCALEOUTEXECUTION"),
"EXPAND": ("VIEWS",),
"FORCE": ("EXTERNALPUSHDOWN", "ORDER", "SCALEOUTEXECUTION"),
"HASH": ("GROUP", "JOIN", "UNION"),
"KEEP": ("PLAN",),
"KEEPFIXED": ("PLAN",),
"LOOP": ("JOIN",),
"MERGE": ("JOIN", "UNION"),
"OPTIMIZE": (("FOR", "UNKNOWN"),),
"ORDER": ("GROUP",),
"PARAMETERIZATION": ("FORCED", "SIMPLE"),
"ROBUST": ("PLAN",),
"USE": ("PLAN",),
}
OPTIONS_THAT_REQUIRE_EQUAL = ("MAX_GRANT_PERCENT", "MIN_GRANT_PERCENT", "LABEL")
def _build_formatted_time(
exp_class: t.Type[E], full_format_mapping: t.Optional[bool] = None
@ -221,19 +258,17 @@ def qualify_derived_table_outputs(expression: exp.Expression) -> exp.Expression:
# We keep track of the unaliased column projection indexes instead of the expressions
# themselves, because the latter are going to be replaced by new nodes when the aliases
# are added and hence we won't be able to reach these newly added Alias parents
subqueryable = expression.this
query = expression.this
unaliased_column_indexes = (
i
for i, c in enumerate(subqueryable.selects)
if isinstance(c, exp.Column) and not c.alias
i for i, c in enumerate(query.selects) if isinstance(c, exp.Column) and not c.alias
)
qualify_outputs(subqueryable)
qualify_outputs(query)
# Preserve the quoting information of columns for newly added Alias nodes
subqueryable_selects = subqueryable.selects
query_selects = query.selects
for select_index in unaliased_column_indexes:
alias = subqueryable_selects[select_index]
alias = query_selects[select_index]
column = alias.this
if isinstance(column.this, exp.Identifier):
alias.args["alias"].set("quoted", column.this.quoted)
@ -420,7 +455,6 @@ class TSQL(Dialect):
"IMAGE": TokenType.IMAGE,
"MONEY": TokenType.MONEY,
"NTEXT": TokenType.TEXT,
"NVARCHAR(MAX)": TokenType.TEXT,
"PRINT": TokenType.COMMAND,
"PROC": TokenType.PROCEDURE,
"REAL": TokenType.FLOAT,
@ -431,15 +465,24 @@ class TSQL(Dialect):
"TOP": TokenType.TOP,
"UNIQUEIDENTIFIER": TokenType.UNIQUEIDENTIFIER,
"UPDATE STATISTICS": TokenType.COMMAND,
"VARCHAR(MAX)": TokenType.TEXT,
"XML": TokenType.XML,
"OUTPUT": TokenType.RETURNING,
"SYSTEM_USER": TokenType.CURRENT_USER,
"FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
"OPTION": TokenType.OPTION,
}
class Parser(parser.Parser):
SET_REQUIRES_ASSIGNMENT_DELIMITER = False
LOG_DEFAULTS_TO_LN = True
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
STRING_ALIASES = True
NO_PAREN_IF_COMMANDS = False
QUERY_MODIFIER_PARSERS = {
**parser.Parser.QUERY_MODIFIER_PARSERS,
TokenType.OPTION: lambda self: ("options", self._parse_options()),
}
FUNCTIONS = {
**parser.Parser.FUNCTIONS,
@ -472,19 +515,7 @@ class TSQL(Dialect):
"TIMEFROMPARTS": _build_timefromparts,
}
JOIN_HINTS = {
"LOOP",
"HASH",
"MERGE",
"REMOTE",
}
VAR_LENGTH_DATATYPES = {
DataType.Type.NVARCHAR,
DataType.Type.VARCHAR,
DataType.Type.CHAR,
DataType.Type.NCHAR,
}
JOIN_HINTS = {"LOOP", "HASH", "MERGE", "REMOTE"}
RETURNS_TABLE_TOKENS = parser.Parser.ID_VAR_TOKENS - {
TokenType.TABLE,
@ -496,11 +527,21 @@ class TSQL(Dialect):
TokenType.END: lambda self: self._parse_command(),
}
LOG_DEFAULTS_TO_LN = True
def _parse_options(self) -> t.Optional[t.List[exp.Expression]]:
if not self._match(TokenType.OPTION):
return None
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
STRING_ALIASES = True
NO_PAREN_IF_COMMANDS = False
def _parse_option() -> t.Optional[exp.Expression]:
option = self._parse_var_from_options(OPTIONS)
if not option:
return None
self._match(TokenType.EQ)
return self.expression(
exp.QueryOption, this=option, expression=self._parse_primary_or_var()
)
return self._parse_wrapped_csv(_parse_option)
def _parse_projections(self) -> t.List[exp.Expression]:
"""
@ -576,48 +617,13 @@ class TSQL(Dialect):
def _parse_convert(
self, strict: bool, safe: t.Optional[bool] = None
) -> t.Optional[exp.Expression]:
to = self._parse_types()
this = self._parse_types()
self._match(TokenType.COMMA)
this = self._parse_conjunction()
if not to or not this:
return None
# Retrieve length of datatype and override to default if not specified
if seq_get(to.expressions, 0) is None and to.this in self.VAR_LENGTH_DATATYPES:
to = exp.DataType.build(to.this, expressions=[exp.Literal.number(30)], nested=False)
# Check whether a conversion with format is applicable
if self._match(TokenType.COMMA):
format_val = self._parse_number()
format_val_name = format_val.name if format_val else ""
if format_val_name not in TSQL.CONVERT_FORMAT_MAPPING:
raise ValueError(
f"CONVERT function at T-SQL does not support format style {format_val_name}"
)
format_norm = exp.Literal.string(TSQL.CONVERT_FORMAT_MAPPING[format_val_name])
# Check whether the convert entails a string to date format
if to.this == DataType.Type.DATE:
return self.expression(exp.StrToDate, this=this, format=format_norm)
# Check whether the convert entails a string to datetime format
elif to.this == DataType.Type.DATETIME:
return self.expression(exp.StrToTime, this=this, format=format_norm)
# Check whether the convert entails a date to string format
elif to.this in self.VAR_LENGTH_DATATYPES:
return self.expression(
exp.Cast if strict else exp.TryCast,
to=to,
this=self.expression(exp.TimeToStr, this=this, format=format_norm),
safe=safe,
)
elif to.this == DataType.Type.TEXT:
return self.expression(exp.TimeToStr, this=this, format=format_norm)
# Entails a simple cast without any format requirement
return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
args = [this, *self._parse_csv(self._parse_conjunction)]
convert = exp.Convert.from_arg_list(args)
convert.set("safe", safe)
convert.set("strict", strict)
return convert
def _parse_user_defined_function(
self, kind: t.Optional[TokenType] = None
@ -683,6 +689,26 @@ class TSQL(Dialect):
return self.expression(exp.UniqueColumnConstraint, this=this)
def _parse_partition(self) -> t.Optional[exp.Partition]:
if not self._match_text_seq("WITH", "(", "PARTITIONS"):
return None
def parse_range():
low = self._parse_bitwise()
high = self._parse_bitwise() if self._match_text_seq("TO") else None
return (
self.expression(exp.PartitionRange, this=low, expression=high) if high else low
)
partition = self.expression(
exp.Partition, expressions=self._parse_wrapped_csv(parse_range)
)
self._match_r_paren()
return partition
class Generator(generator.Generator):
LIMIT_IS_TOP = True
QUERY_HINTS = False
@ -728,6 +754,9 @@ class TSQL(Dialect):
exp.DataType.Type.VARIANT: "SQL_VARIANT",
}
TYPE_MAPPING.pop(exp.DataType.Type.NCHAR)
TYPE_MAPPING.pop(exp.DataType.Type.NVARCHAR)
TRANSFORMS = {
**generator.Generator.TRANSFORMS,
exp.AnyValue: any_value_to_max_sql,
@ -779,6 +808,20 @@ class TSQL(Dialect):
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
}
def convert_sql(self, expression: exp.Convert) -> str:
name = "TRY_CONVERT" if expression.args.get("safe") else "CONVERT"
return self.func(
name, expression.this, expression.expression, expression.args.get("style")
)
def queryoption_sql(self, expression: exp.QueryOption) -> str:
option = self.sql(expression, "this")
value = self.sql(expression, "expression")
if value:
optional_equal_sign = "= " if option in OPTIONS_THAT_REQUIRE_EQUAL else ""
return f"{option} {optional_equal_sign}{value}"
return option
def lateral_op(self, expression: exp.Lateral) -> str:
cross_apply = expression.args.get("cross_apply")
if cross_apply is True:
@ -876,11 +919,10 @@ class TSQL(Dialect):
if ctas_with:
ctas_with = ctas_with.pop()
subquery = ctas_expression
if isinstance(subquery, exp.Subqueryable):
subquery = subquery.subquery()
if isinstance(ctas_expression, exp.UNWRAPPED_QUERIES):
ctas_expression = ctas_expression.subquery()
select_into = exp.select("*").from_(exp.alias_(subquery, "temp", table=True))
select_into = exp.select("*").from_(exp.alias_(ctas_expression, "temp", table=True))
select_into.set("into", exp.Into(this=table))
select_into.set("with", ctas_with)
@ -993,3 +1035,6 @@ class TSQL(Dialect):
this_sql = self.sql(this)
expression_sql = self.sql(expression, "expression")
return self.func(name, this_sql, expression_sql if expression_sql else None)
def partition_sql(self, expression: exp.Partition) -> str:
return f"WITH (PARTITIONS({self.expressions(expression, flat=True)}))"

View file

@ -119,13 +119,18 @@ def diff(
return ChangeDistiller(**kwargs).diff(source_copy, target_copy, matchings=matchings_copy)
LEAF_EXPRESSION_TYPES = (
# The expression types for which Update edits are allowed.
UPDATABLE_EXPRESSION_TYPES = (
exp.Boolean,
exp.DataType,
exp.Identifier,
exp.Literal,
exp.Table,
exp.Column,
exp.Lambda,
)
IGNORED_LEAF_EXPRESSION_TYPES = (exp.Identifier,)
class ChangeDistiller:
"""
@ -152,8 +157,16 @@ class ChangeDistiller:
self._source = source
self._target = target
self._source_index = {id(n): n for n, *_ in self._source.bfs()}
self._target_index = {id(n): n for n, *_ in self._target.bfs()}
self._source_index = {
id(n): n
for n, *_ in self._source.bfs()
if not isinstance(n, IGNORED_LEAF_EXPRESSION_TYPES)
}
self._target_index = {
id(n): n
for n, *_ in self._target.bfs()
if not isinstance(n, IGNORED_LEAF_EXPRESSION_TYPES)
}
self._unmatched_source_nodes = set(self._source_index) - set(pre_matched_nodes)
self._unmatched_target_nodes = set(self._target_index) - set(pre_matched_nodes.values())
self._bigram_histo_cache: t.Dict[int, t.DefaultDict[str, int]] = {}
@ -170,7 +183,10 @@ class ChangeDistiller:
for kept_source_node_id, kept_target_node_id in matching_set:
source_node = self._source_index[kept_source_node_id]
target_node = self._target_index[kept_target_node_id]
if not isinstance(source_node, LEAF_EXPRESSION_TYPES) or source_node == target_node:
if (
not isinstance(source_node, UPDATABLE_EXPRESSION_TYPES)
or source_node == target_node
):
edit_script.extend(
self._generate_move_edits(source_node, target_node, matching_set)
)
@ -307,6 +323,7 @@ def _get_leaves(expression: exp.Expression) -> t.Iterator[exp.Expression]:
has_child_exprs = False
for _, node in expression.iter_expressions():
if not isinstance(node, IGNORED_LEAF_EXPRESSION_TYPES):
has_child_exprs = True
yield from _get_leaves(node)
@ -315,9 +332,7 @@ def _get_leaves(expression: exp.Expression) -> t.Iterator[exp.Expression]:
def _is_same_type(source: exp.Expression, target: exp.Expression) -> bool:
if type(source) is type(target) and (
not isinstance(source, exp.Identifier) or type(source.parent) is type(target.parent)
):
if type(source) is type(target):
if isinstance(source, exp.Join):
return source.args.get("side") == target.args.get("side")
@ -343,7 +358,11 @@ def _expression_only_args(expression: exp.Expression) -> t.List[exp.Expression]:
if expression:
for a in expression.args.values():
args.extend(ensure_list(a))
return [a for a in args if isinstance(a, exp.Expression)]
return [
a
for a in args
if isinstance(a, exp.Expression) and not isinstance(a, IGNORED_LEAF_EXPRESSION_TYPES)
]
def _lcs(

View file

@ -78,7 +78,7 @@ class Context:
def sort(self, key) -> None:
def sort_key(row: t.Tuple) -> t.Tuple:
self.set_row(row)
return self.eval_tuple(key)
return tuple((t is None, t) for t in self.eval_tuple(key))
self.table.rows.sort(key=sort_key)

View file

@ -142,7 +142,6 @@ class PythonExecutor:
context = self.context({alias: table})
yield context
types = []
for row in reader:
if not types:
for v in row:
@ -150,7 +149,11 @@ class PythonExecutor:
types.append(type(ast.literal_eval(v)))
except (ValueError, SyntaxError):
types.append(str)
context.set_row(tuple(t(v) for t, v in zip(types, row)))
# We can't cast empty values ('') to non-string types, so we convert them to None instead
context.set_row(
tuple(None if (t is not str and v == "") else t(v) for t, v in zip(types, row))
)
yield context.table.reader
def join(self, step, context):

View file

@ -548,12 +548,10 @@ class Expression(metaclass=_Expression):
return new_node
@t.overload
def replace(self, expression: E) -> E:
...
def replace(self, expression: E) -> E: ...
@t.overload
def replace(self, expression: None) -> None:
...
def replace(self, expression: None) -> None: ...
def replace(self, expression):
"""
@ -913,14 +911,142 @@ class Predicate(Condition):
class DerivedTable(Expression):
@property
def selects(self) -> t.List[Expression]:
return self.this.selects if isinstance(self.this, Subqueryable) else []
return self.this.selects if isinstance(self.this, Query) else []
@property
def named_selects(self) -> t.List[str]:
return [select.output_name for select in self.selects]
class Unionable(Expression):
class Query(Expression):
def subquery(self, alias: t.Optional[ExpOrStr] = None, copy: bool = True) -> Subquery:
"""
Returns a `Subquery` that wraps around this query.
Example:
>>> subquery = Select().select("x").from_("tbl").subquery()
>>> Select().select("x").from_(subquery).sql()
'SELECT x FROM (SELECT x FROM tbl)'
Args:
alias: an optional alias for the subquery.
copy: if `False`, modify this expression instance in-place.
"""
instance = maybe_copy(self, copy)
if not isinstance(alias, Expression):
alias = TableAlias(this=to_identifier(alias)) if alias else None
return Subquery(this=instance, alias=alias)
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Adds a LIMIT clause to this query.
Example:
>>> select("1").union(select("1")).limit(1).sql()
'SELECT * FROM (SELECT 1 UNION SELECT 1) AS _l_0 LIMIT 1'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, it will be used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
A limited Select expression.
"""
return (
select("*")
.from_(self.subquery(alias="_l_0", copy=copy))
.limit(expression, dialect=dialect, copy=False, **opts)
)
@property
def ctes(self) -> t.List[CTE]:
"""Returns a list of all the CTEs attached to this query."""
with_ = self.args.get("with")
return with_.expressions if with_ else []
@property
def selects(self) -> t.List[Expression]:
"""Returns the query's projections."""
raise NotImplementedError("Query objects must implement `selects`")
@property
def named_selects(self) -> t.List[str]:
"""Returns the output names of the query's projections."""
raise NotImplementedError("Query objects must implement `named_selects`")
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Query:
"""
Append to or set the SELECT expressions.
Example:
>>> Select().select("x", "y").sql()
'SELECT x, y'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified Query expression.
"""
raise NotImplementedError("Query objects must implement `select`")
def with_(
self,
alias: ExpOrStr,
as_: ExpOrStr,
recursive: t.Optional[bool] = None,
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Query:
"""
Append to or set the common table expressions.
Example:
>>> Select().with_("tbl2", as_="SELECT * FROM tbl").select("x").from_("tbl2").sql()
'WITH tbl2 AS (SELECT * FROM tbl) SELECT x FROM tbl2'
Args:
alias: the SQL code string to parse as the table name.
If an `Expression` instance is passed, this is used as-is.
as_: the SQL code string to parse as the table expression.
If an `Expression` instance is passed, it will be used as-is.
recursive: set the RECURSIVE part of the expression. Defaults to `False`.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified expression.
"""
return _apply_cte_builder(
self, alias, as_, recursive=recursive, append=append, dialect=dialect, copy=copy, **opts
)
def union(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Union:
@ -946,7 +1072,7 @@ class Unionable(Expression):
def intersect(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable:
) -> Intersect:
"""
Builds an INTERSECT expression.
@ -969,7 +1095,7 @@ class Unionable(Expression):
def except_(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable:
) -> Except:
"""
Builds an EXCEPT expression.
@ -991,7 +1117,7 @@ class Unionable(Expression):
return except_(left=self, right=expression, distinct=distinct, dialect=dialect, **opts)
class UDTF(DerivedTable, Unionable):
class UDTF(DerivedTable):
@property
def selects(self) -> t.List[Expression]:
alias = self.args.get("alias")
@ -1017,23 +1143,23 @@ class Refresh(Expression):
class DDL(Expression):
@property
def ctes(self):
def ctes(self) -> t.List[CTE]:
"""Returns a list of all the CTEs attached to this statement."""
with_ = self.args.get("with")
if not with_:
return []
return with_.expressions
@property
def named_selects(self) -> t.List[str]:
if isinstance(self.expression, Subqueryable):
return self.expression.named_selects
return []
return with_.expressions if with_ else []
@property
def selects(self) -> t.List[Expression]:
if isinstance(self.expression, Subqueryable):
return self.expression.selects
return []
"""If this statement contains a query (e.g. a CTAS), this returns the query's projections."""
return self.expression.selects if isinstance(self.expression, Query) else []
@property
def named_selects(self) -> t.List[str]:
"""
If this statement contains a query (e.g. a CTAS), this returns the output
names of the query's projections.
"""
return self.expression.named_selects if isinstance(self.expression, Query) else []
class DML(Expression):
@ -1096,6 +1222,19 @@ class Create(DDL):
return kind and kind.upper()
class TruncateTable(Expression):
arg_types = {
"expressions": True,
"is_database": False,
"exists": False,
"only": False,
"cluster": False,
"identity": False,
"option": False,
"partition": False,
}
# https://docs.snowflake.com/en/sql-reference/sql/create-clone
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_clone_statement
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_copy
@ -1271,6 +1410,10 @@ class ColumnDef(Expression):
def constraints(self) -> t.List[ColumnConstraint]:
return self.args.get("constraints") or []
@property
def kind(self) -> t.Optional[DataType]:
return self.args.get("kind")
class AlterColumn(Expression):
arg_types = {
@ -1367,7 +1510,7 @@ class CharacterSetColumnConstraint(ColumnConstraintKind):
class CheckColumnConstraint(ColumnConstraintKind):
pass
arg_types = {"this": True, "enforced": False}
class ClusteredColumnConstraint(ColumnConstraintKind):
@ -1776,6 +1919,10 @@ class Partition(Expression):
arg_types = {"expressions": True}
class PartitionRange(Expression):
arg_types = {"this": True, "expression": True}
class Fetch(Expression):
arg_types = {
"direction": False,
@ -2173,6 +2320,10 @@ class LocationProperty(Property):
arg_types = {"this": True}
class LockProperty(Property):
arg_types = {"this": True}
class LockingProperty(Property):
arg_types = {
"this": False,
@ -2310,7 +2461,7 @@ class StabilityProperty(Property):
class TemporaryProperty(Property):
arg_types = {}
arg_types = {"this": False}
class TransformModelProperty(Property):
@ -2356,6 +2507,7 @@ class Properties(Expression):
"FORMAT": FileFormatProperty,
"LANGUAGE": LanguageProperty,
"LOCATION": LocationProperty,
"LOCK": LockProperty,
"PARTITIONED_BY": PartitionedByProperty,
"RETURNS": ReturnsProperty,
"ROW_FORMAT": RowFormatProperty,
@ -2445,102 +2597,13 @@ class Tuple(Expression):
)
class Subqueryable(Unionable):
def subquery(self, alias: t.Optional[ExpOrStr] = None, copy: bool = True) -> Subquery:
"""
Convert this expression to an aliased expression that can be used as a Subquery.
Example:
>>> subquery = Select().select("x").from_("tbl").subquery()
>>> Select().select("x").from_(subquery).sql()
'SELECT x FROM (SELECT x FROM tbl)'
Args:
alias (str | Identifier): an optional alias for the subquery
copy (bool): if `False`, modify this expression instance in-place.
Returns:
Alias: the subquery
"""
instance = maybe_copy(self, copy)
if not isinstance(alias, Expression):
alias = TableAlias(this=to_identifier(alias)) if alias else None
return Subquery(this=instance, alias=alias)
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
raise NotImplementedError
@property
def ctes(self):
with_ = self.args.get("with")
if not with_:
return []
return with_.expressions
@property
def selects(self) -> t.List[Expression]:
raise NotImplementedError("Subqueryable objects must implement `selects`")
@property
def named_selects(self) -> t.List[str]:
raise NotImplementedError("Subqueryable objects must implement `named_selects`")
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subqueryable:
raise NotImplementedError("Subqueryable objects must implement `select`")
def with_(
self,
alias: ExpOrStr,
as_: ExpOrStr,
recursive: t.Optional[bool] = None,
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subqueryable:
"""
Append to or set the common table expressions.
Example:
>>> Select().with_("tbl2", as_="SELECT * FROM tbl").select("x").from_("tbl2").sql()
'WITH tbl2 AS (SELECT * FROM tbl) SELECT x FROM tbl2'
Args:
alias: the SQL code string to parse as the table name.
If an `Expression` instance is passed, this is used as-is.
as_: the SQL code string to parse as the table expression.
If an `Expression` instance is passed, it will be used as-is.
recursive: set the RECURSIVE part of the expression. Defaults to `False`.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified expression.
"""
return _apply_cte_builder(
self, alias, as_, recursive=recursive, append=append, dialect=dialect, copy=copy, **opts
)
QUERY_MODIFIERS = {
"match": False,
"laterals": False,
"joins": False,
"connect": False,
"pivots": False,
"prewhere": False,
"where": False,
"group": False,
"having": False,
@ -2556,9 +2619,16 @@ QUERY_MODIFIERS = {
"sample": False,
"settings": False,
"format": False,
"options": False,
}
# https://learn.microsoft.com/en-us/sql/t-sql/queries/option-clause-transact-sql?view=sql-server-ver16
# https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query?view=sql-server-ver16
class QueryOption(Expression):
arg_types = {"this": True, "expression": False}
# https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
class WithTableHint(Expression):
arg_types = {"expressions": True}
@ -2590,6 +2660,7 @@ class Table(Expression):
"pattern": False,
"ordinality": False,
"when": False,
"only": False,
}
@property
@ -2638,7 +2709,7 @@ class Table(Expression):
return col
class Union(Subqueryable):
class Union(Query):
arg_types = {
"with": False,
"this": True,
@ -2648,34 +2719,6 @@ class Union(Subqueryable):
**QUERY_MODIFIERS,
}
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Set the LIMIT expression.
Example:
>>> select("1").union(select("1")).limit(1).sql()
'SELECT * FROM (SELECT 1 UNION SELECT 1) AS _l_0 LIMIT 1'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, this is used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The limited subqueryable.
"""
return (
select("*")
.from_(self.subquery(alias="_l_0", copy=copy))
.limit(expression, dialect=dialect, copy=False, **opts)
)
def select(
self,
*expressions: t.Optional[ExpOrStr],
@ -2684,26 +2727,7 @@ class Union(Subqueryable):
copy: bool = True,
**opts,
) -> Union:
"""Append to or set the SELECT of the union recursively.
Example:
>>> from sqlglot import parse_one
>>> parse_one("select a from x union select a from y union select a from z").select("b").sql()
'SELECT a, b FROM x UNION SELECT a, b FROM y UNION SELECT a, b FROM z'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
Union: the modified expression.
"""
this = self.copy() if copy else self
this = maybe_copy(self, copy)
this.this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts)
this.expression.unnest().select(
*expressions, append=append, dialect=dialect, copy=False, **opts
@ -2800,7 +2824,7 @@ class Lock(Expression):
arg_types = {"update": True, "expressions": False, "wait": False}
class Select(Subqueryable):
class Select(Query):
arg_types = {
"with": False,
"kind": False,
@ -3011,25 +3035,6 @@ class Select(Subqueryable):
def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select:
"""
Set the LIMIT expression.
Example:
>>> Select().from_("tbl").select("x").limit(10).sql()
'SELECT x FROM tbl LIMIT 10'
Args:
expression: the SQL code string to parse.
This can also be an integer.
If a `Limit` instance is passed, this is used as-is.
If another `Expression` instance is passed, it will be wrapped in a `Limit`.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
Select: the modified expression.
"""
return _apply_builder(
expression=expression,
instance=self,
@ -3084,31 +3089,13 @@ class Select(Subqueryable):
copy: bool = True,
**opts,
) -> Select:
"""
Append to or set the SELECT expressions.
Example:
>>> Select().select("x", "y").sql()
'SELECT x, y'
Args:
*expressions: the SQL code strings to parse.
If an `Expression` instance is passed, it will be used as-is.
append: if `True`, add to any existing expressions.
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expressions.
copy: if `False`, modify this expression instance in-place.
opts: other options to use to parse the input expressions.
Returns:
The modified Select expression.
"""
return _apply_list_builder(
*expressions,
instance=self,
arg="expressions",
append=append,
dialect=dialect,
into=Expression,
copy=copy,
**opts,
)
@ -3416,12 +3403,8 @@ class Select(Subqueryable):
The new Create expression.
"""
instance = maybe_copy(self, copy)
table_expression = maybe_parse(
table,
into=Table,
dialect=dialect,
**opts,
)
table_expression = maybe_parse(table, into=Table, dialect=dialect, **opts)
properties_expression = None
if properties:
properties_expression = Properties.from_dict(properties)
@ -3493,7 +3476,10 @@ class Select(Subqueryable):
return self.expressions
class Subquery(DerivedTable, Unionable):
UNWRAPPED_QUERIES = (Select, Union)
class Subquery(DerivedTable, Query):
arg_types = {
"this": True,
"alias": False,
@ -3502,9 +3488,7 @@ class Subquery(DerivedTable, Unionable):
}
def unnest(self):
"""
Returns the first non subquery.
"""
"""Returns the first non subquery."""
expression = self
while isinstance(expression, Subquery):
expression = expression.this
@ -3516,6 +3500,18 @@ class Subquery(DerivedTable, Unionable):
expression = t.cast(Subquery, expression.parent)
return expression
def select(
self,
*expressions: t.Optional[ExpOrStr],
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
**opts,
) -> Subquery:
this = maybe_copy(self, copy)
this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts)
return this
@property
def is_wrapper(self) -> bool:
"""
@ -3603,6 +3599,10 @@ class WindowSpec(Expression):
}
class PreWhere(Expression):
pass
class Where(Expression):
pass
@ -3646,6 +3646,10 @@ class Boolean(Condition):
class DataTypeParam(Expression):
arg_types = {"this": True, "expression": False}
@property
def name(self) -> str:
return self.this.name
class DataType(Expression):
arg_types = {
@ -3926,11 +3930,17 @@ class Rollback(Expression):
class AlterTable(Expression):
arg_types = {"this": True, "actions": True, "exists": False, "only": False}
arg_types = {
"this": True,
"actions": True,
"exists": False,
"only": False,
"options": False,
}
class AddConstraint(Expression):
arg_types = {"this": False, "expression": False, "enforced": False}
arg_types = {"expressions": True}
class DropPartition(Expression):
@ -3995,6 +4005,10 @@ class Overlaps(Binary):
class Dot(Binary):
@property
def is_star(self) -> bool:
return self.expression.is_star
@property
def name(self) -> str:
return self.expression.name
@ -4390,6 +4404,10 @@ class Anonymous(Func):
arg_types = {"this": True, "expressions": False}
is_var_len_args = True
@property
def name(self) -> str:
return self.this if isinstance(self.this, str) else self.this.name
class AnonymousAggFunc(AggFunc):
arg_types = {"this": True, "expressions": False}
@ -4433,8 +4451,13 @@ class ToChar(Func):
arg_types = {"this": True, "format": False, "nlsparam": 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}
class GenerateSeries(Func):
arg_types = {"start": True, "end": True, "step": False}
arg_types = {"start": True, "end": True, "step": False, "is_end_exclusive": False}
class ArrayAgg(AggFunc):
@ -4624,6 +4647,11 @@ class ConcatWs(Concat):
_sql_names = ["CONCAT_WS"]
# https://docs.oracle.com/cd/B13789_01/server.101/b10759/operators004.htm#i1035022
class ConnectByRoot(Func):
pass
class Count(AggFunc):
arg_types = {"this": False, "expressions": False}
is_var_len_args = True
@ -5197,6 +5225,10 @@ class Month(Func):
pass
class AddMonths(Func):
arg_types = {"this": True, "expression": True}
class Nvl2(Func):
arg_types = {"this": True, "true": True, "false": False}
@ -5313,6 +5345,10 @@ class SHA2(Func):
arg_types = {"this": True, "length": False}
class Sign(Func):
_sql_names = ["SIGN", "SIGNUM"]
class SortArray(Func):
arg_types = {"this": True, "asc": False}
@ -5554,7 +5590,13 @@ class Use(Expression):
class Merge(Expression):
arg_types = {"this": True, "using": True, "on": True, "expressions": True, "with": False}
arg_types = {
"this": True,
"using": True,
"on": True,
"expressions": True,
"with": False,
}
class When(Func):
@ -5587,8 +5629,7 @@ def maybe_parse(
prefix: t.Optional[str] = None,
copy: bool = False,
**opts,
) -> E:
...
) -> E: ...
@t.overload
@ -5600,8 +5641,7 @@ def maybe_parse(
prefix: t.Optional[str] = None,
copy: bool = False,
**opts,
) -> E:
...
) -> E: ...
def maybe_parse(
@ -5653,13 +5693,11 @@ def maybe_parse(
@t.overload
def maybe_copy(instance: None, copy: bool = True) -> None:
...
def maybe_copy(instance: None, copy: bool = True) -> None: ...
@t.overload
def maybe_copy(instance: E, copy: bool = True) -> E:
...
def maybe_copy(instance: E, copy: bool = True) -> E: ...
def maybe_copy(instance, copy=True):
@ -6282,15 +6320,13 @@ SAFE_IDENTIFIER_RE: t.Pattern[str] = re.compile(r"^[_a-zA-Z][\w]*$")
@t.overload
def to_identifier(name: None, quoted: t.Optional[bool] = None, copy: bool = True) -> None:
...
def to_identifier(name: None, quoted: t.Optional[bool] = None, copy: bool = True) -> None: ...
@t.overload
def to_identifier(
name: str | Identifier, quoted: t.Optional[bool] = None, copy: bool = True
) -> Identifier:
...
) -> Identifier: ...
def to_identifier(name, quoted=None, copy=True):
@ -6362,13 +6398,11 @@ def to_interval(interval: str | Literal) -> Interval:
@t.overload
def to_table(sql_path: str | Table, **kwargs) -> Table:
...
def to_table(sql_path: str | Table, **kwargs) -> Table: ...
@t.overload
def to_table(sql_path: None, **kwargs) -> None:
...
def to_table(sql_path: None, **kwargs) -> None: ...
def to_table(
@ -6929,7 +6963,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
if isinstance(node, Placeholder):
if node.name:
new_name = kwargs.get(node.name)
if new_name:
if new_name is not None:
return convert(new_name)
else:
try:
@ -6943,7 +6977,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
def expand(
expression: Expression,
sources: t.Dict[str, Subqueryable],
sources: t.Dict[str, Query],
dialect: DialectType = None,
copy: bool = True,
) -> Expression:
@ -6959,7 +6993,7 @@ def expand(
Args:
expression: The expression to expand.
sources: A dictionary of name to Subqueryables.
sources: A dictionary of name to Queries.
dialect: The dialect of the sources dict.
copy: Whether to copy the expression during transformation. Defaults to True.

View file

@ -73,17 +73,16 @@ class Generator(metaclass=_Generator):
TRANSFORMS: t.Dict[t.Type[exp.Expression], t.Callable[..., str]] = {
**JSON_PATH_PART_TRANSFORMS,
exp.AutoRefreshProperty: lambda self, e: f"AUTO REFRESH {self.sql(e, 'this')}",
exp.CaseSpecificColumnConstraint: lambda self,
exp.CaseSpecificColumnConstraint: lambda _,
e: f"{'NOT ' if e.args.get('not_') else ''}CASESPECIFIC",
exp.CharacterSetColumnConstraint: lambda self, e: f"CHARACTER SET {self.sql(e, 'this')}",
exp.CharacterSetProperty: lambda self,
e: f"{'DEFAULT ' if e.args.get('default') else ''}CHARACTER SET={self.sql(e, 'this')}",
exp.CheckColumnConstraint: lambda self, e: f"CHECK ({self.sql(e, 'this')})",
exp.ClusteredColumnConstraint: lambda self,
e: f"CLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}",
exp.CommentColumnConstraint: lambda self, e: f"COMMENT {self.sql(e, 'this')}",
exp.CopyGrantsProperty: lambda self, e: "COPY GRANTS",
exp.CopyGrantsProperty: lambda *_: "COPY GRANTS",
exp.DateAdd: lambda self, e: self.func(
"DATE_ADD", e.this, e.expression, exp.Literal.string(e.text("unit"))
),
@ -91,8 +90,8 @@ class Generator(metaclass=_Generator):
exp.DefaultColumnConstraint: lambda self, e: f"DEFAULT {self.sql(e, 'this')}",
exp.EncodeColumnConstraint: lambda self, e: f"ENCODE {self.sql(e, 'this')}",
exp.ExecuteAsProperty: lambda self, e: self.naked_property(e),
exp.ExternalProperty: lambda self, e: "EXTERNAL",
exp.HeapProperty: lambda self, e: "HEAP",
exp.ExternalProperty: lambda *_: "EXTERNAL",
exp.HeapProperty: lambda *_: "HEAP",
exp.InheritsProperty: lambda self, e: f"INHERITS ({self.expressions(e, flat=True)})",
exp.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}",
exp.InputModelProperty: lambda self, e: f"INPUT{self.sql(e, 'this')}",
@ -105,13 +104,13 @@ class Generator(metaclass=_Generator):
),
exp.LanguageProperty: lambda self, e: self.naked_property(e),
exp.LocationProperty: lambda self, e: self.naked_property(e),
exp.LogProperty: lambda self, e: f"{'NO ' if e.args.get('no') else ''}LOG",
exp.MaterializedProperty: lambda self, e: "MATERIALIZED",
exp.LogProperty: lambda _, e: f"{'NO ' if e.args.get('no') else ''}LOG",
exp.MaterializedProperty: lambda *_: "MATERIALIZED",
exp.NonClusteredColumnConstraint: lambda self,
e: f"NONCLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.NoPrimaryIndexProperty: lambda self, e: "NO PRIMARY INDEX",
exp.NotForReplicationColumnConstraint: lambda self, e: "NOT FOR REPLICATION",
exp.OnCommitProperty: lambda self,
exp.NoPrimaryIndexProperty: lambda *_: "NO PRIMARY INDEX",
exp.NotForReplicationColumnConstraint: lambda *_: "NOT FOR REPLICATION",
exp.OnCommitProperty: lambda _,
e: f"ON COMMIT {'DELETE' if e.args.get('delete') else 'PRESERVE'} ROWS",
exp.OnProperty: lambda self, e: f"ON {self.sql(e, 'this')}",
exp.OnUpdateColumnConstraint: lambda self, e: f"ON UPDATE {self.sql(e, 'this')}",
@ -122,21 +121,21 @@ class Generator(metaclass=_Generator):
exp.ReturnsProperty: lambda self, e: self.naked_property(e),
exp.SampleProperty: lambda self, e: f"SAMPLE BY {self.sql(e, 'this')}",
exp.SetConfigProperty: lambda self, e: self.sql(e, "this"),
exp.SetProperty: lambda self, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
exp.SetProperty: lambda _, e: f"{'MULTI' if e.args.get('multi') else ''}SET",
exp.SettingsProperty: lambda self, e: f"SETTINGS{self.seg('')}{(self.expressions(e))}",
exp.SqlReadWriteProperty: lambda self, e: e.name,
exp.SqlSecurityProperty: lambda self,
exp.SqlReadWriteProperty: lambda _, e: e.name,
exp.SqlSecurityProperty: lambda _,
e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}",
exp.StabilityProperty: lambda self, e: e.name,
exp.TemporaryProperty: lambda self, e: "TEMPORARY",
exp.StabilityProperty: lambda _, e: e.name,
exp.TemporaryProperty: lambda *_: "TEMPORARY",
exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}",
exp.Timestamp: lambda self, e: self.func("TIMESTAMP", e.this, e.expression),
exp.ToTableProperty: lambda self, e: f"TO {self.sql(e.this)}",
exp.TransformModelProperty: lambda self, e: self.func("TRANSFORM", *e.expressions),
exp.TransientProperty: lambda self, e: "TRANSIENT",
exp.UppercaseColumnConstraint: lambda self, e: "UPPERCASE",
exp.TransientProperty: lambda *_: "TRANSIENT",
exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]),
exp.VolatileProperty: lambda self, e: "VOLATILE",
exp.VolatileProperty: lambda *_: "VOLATILE",
exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}",
}
@ -356,6 +355,7 @@ class Generator(metaclass=_Generator):
STRUCT_DELIMITER = ("<", ">")
PARAMETER_TOKEN = "@"
NAMED_PLACEHOLDER_TOKEN = ":"
PROPERTIES_LOCATION = {
exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
@ -388,6 +388,7 @@ class Generator(metaclass=_Generator):
exp.LanguageProperty: exp.Properties.Location.POST_SCHEMA,
exp.LikeProperty: exp.Properties.Location.POST_SCHEMA,
exp.LocationProperty: exp.Properties.Location.POST_SCHEMA,
exp.LockProperty: exp.Properties.Location.POST_SCHEMA,
exp.LockingProperty: exp.Properties.Location.POST_ALIAS,
exp.LogProperty: exp.Properties.Location.POST_NAME,
exp.MaterializedProperty: exp.Properties.Location.POST_CREATE,
@ -459,11 +460,16 @@ class Generator(metaclass=_Generator):
exp.Paren,
)
PARAMETERIZABLE_TEXT_TYPES = {
exp.DataType.Type.NVARCHAR,
exp.DataType.Type.VARCHAR,
exp.DataType.Type.CHAR,
exp.DataType.Type.NCHAR,
}
# Expressions that need to have all CTEs under them bubbled up to them
EXPRESSIONS_WITHOUT_NESTED_CTES: t.Set[t.Type[exp.Expression]] = set()
KEY_VALUE_DEFINITIONS = (exp.EQ, exp.PropertyEQ, exp.Slice)
SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
__slots__ = (
@ -630,7 +636,7 @@ class Generator(metaclass=_Generator):
this_sql = self.indent(
(
self.sql(expression)
if isinstance(expression, (exp.Select, exp.Union))
if isinstance(expression, exp.UNWRAPPED_QUERIES)
else self.sql(expression, "this")
),
level=1,
@ -1535,8 +1541,8 @@ class Generator(metaclass=_Generator):
expr = self.sql(expression, "expression")
return f"{this} ({kind} => {expr})"
def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
table = ".".join(
def table_parts(self, expression: exp.Table) -> str:
return ".".join(
self.sql(part)
for part in (
expression.args.get("catalog"),
@ -1546,6 +1552,9 @@ class Generator(metaclass=_Generator):
if part is not None
)
def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str:
table = self.table_parts(expression)
only = "ONLY " if expression.args.get("only") else ""
version = self.sql(expression, "version")
version = f" {version}" if version else ""
alias = self.sql(expression, "alias")
@ -1572,7 +1581,7 @@ class Generator(metaclass=_Generator):
if when:
table = f"{table} {when}"
return f"{table}{version}{file_format}{alias}{hints}{pivots}{joins}{laterals}{ordinality}"
return f"{only}{table}{version}{file_format}{alias}{hints}{pivots}{joins}{laterals}{ordinality}"
def tablesample_sql(
self,
@ -1681,7 +1690,7 @@ class Generator(metaclass=_Generator):
alias_node = expression.args.get("alias")
column_names = alias_node and alias_node.columns
selects: t.List[exp.Subqueryable] = []
selects: t.List[exp.Query] = []
for i, tup in enumerate(expression.expressions):
row = tup.expressions
@ -1697,10 +1706,8 @@ class Generator(metaclass=_Generator):
# This may result in poor performance for large-cardinality `VALUES` tables, due to
# the deep nesting of the resulting exp.Unions. If this is a problem, either increase
# `sys.setrecursionlimit` to avoid RecursionErrors, or don't set `pretty`.
subqueryable = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
return self.subquery_sql(
subqueryable.subquery(alias_node and alias_node.this, copy=False)
)
query = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
return self.subquery_sql(query.subquery(alias_node and alias_node.this, copy=False))
alias = f" AS {self.sql(alias_node, 'this')}" if alias_node else ""
unions = " UNION ALL ".join(self.sql(select) for select in selects)
@ -1854,7 +1861,7 @@ class Generator(metaclass=_Generator):
]
args_sql = ", ".join(self.sql(e) for e in args)
args_sql = f"({args_sql})" if any(top and not e.is_number for e in args) else args_sql
args_sql = f"({args_sql})" if top and any(not e.is_number for e in args) else args_sql
expressions = self.expressions(expression, flat=True)
expressions = f" BY {expressions}" if expressions else ""
@ -2070,12 +2077,17 @@ class Generator(metaclass=_Generator):
else []
)
options = self.expressions(expression, key="options")
if options:
options = f" OPTION{self.wrap(options)}"
return csv(
*sqls,
*[self.sql(join) for join in expression.args.get("joins") or []],
self.sql(expression, "connect"),
self.sql(expression, "match"),
*[self.sql(lateral) for lateral in expression.args.get("laterals") or []],
self.sql(expression, "prewhere"),
self.sql(expression, "where"),
self.sql(expression, "group"),
self.sql(expression, "having"),
@ -2083,9 +2095,13 @@ class Generator(metaclass=_Generator):
self.sql(expression, "order"),
*offset_limit_modifiers,
*self.after_limit_modifiers(expression),
options,
sep="",
)
def queryoption_sql(self, expression: exp.QueryOption) -> str:
return ""
def offset_limit_modifiers(
self, expression: exp.Expression, fetch: bool, limit: t.Optional[exp.Fetch | exp.Limit]
) -> t.List[str]:
@ -2140,9 +2156,9 @@ class Generator(metaclass=_Generator):
self.sql(
exp.Struct(
expressions=[
exp.column(e.output_name).eq(
e.this if isinstance(e, exp.Alias) else e
)
exp.PropertyEQ(this=e.args.get("alias"), expression=e.this)
if isinstance(e, exp.Alias)
else e
for e in expression.expressions
]
)
@ -2204,7 +2220,7 @@ class Generator(metaclass=_Generator):
return f"@@{kind}{this}"
def placeholder_sql(self, expression: exp.Placeholder) -> str:
return f":{expression.name}" if expression.name else "?"
return f"{self.NAMED_PLACEHOLDER_TOKEN}{expression.name}" if expression.name else "?"
def subquery_sql(self, expression: exp.Subquery, sep: str = " AS ") -> str:
alias = self.sql(expression, "alias")
@ -2261,6 +2277,9 @@ class Generator(metaclass=_Generator):
return f"UNNEST({args}){suffix}"
def prewhere_sql(self, expression: exp.PreWhere) -> str:
return ""
def where_sql(self, expression: exp.Where) -> str:
this = self.indent(self.sql(expression, "this"))
return f"{self.seg('WHERE')}{self.sep()}{this}"
@ -2326,7 +2345,7 @@ class Generator(metaclass=_Generator):
def any_sql(self, expression: exp.Any) -> str:
this = self.sql(expression, "this")
if isinstance(expression.this, exp.Subqueryable):
if isinstance(expression.this, exp.UNWRAPPED_QUERIES):
this = self.wrap(this)
return f"ANY {this}"
@ -2568,7 +2587,7 @@ class Generator(metaclass=_Generator):
is_global = " GLOBAL" if expression.args.get("is_global") else ""
if query:
in_sql = self.wrap(query)
in_sql = self.wrap(self.sql(query))
elif unnest:
in_sql = self.in_unnest_op(unnest)
elif field:
@ -2610,7 +2629,7 @@ class Generator(metaclass=_Generator):
return f"REFERENCES {this}{expressions}{options}"
def anonymous_sql(self, expression: exp.Anonymous) -> str:
return self.func(expression.name, *expression.expressions)
return self.func(self.sql(expression, "this"), *expression.expressions)
def paren_sql(self, expression: exp.Paren) -> str:
if isinstance(expression.unnest(), exp.Select):
@ -2822,7 +2841,9 @@ class Generator(metaclass=_Generator):
exists = " IF EXISTS" if expression.args.get("exists") else ""
only = " ONLY" if expression.args.get("only") else ""
return f"ALTER TABLE{exists}{only} {self.sql(expression, 'this')} {actions}"
options = self.expressions(expression, key="options")
options = f", {options}" if options else ""
return f"ALTER TABLE{exists}{only} {self.sql(expression, 'this')} {actions}{options}"
def add_column_sql(self, expression: exp.AlterTable) -> str:
if self.ALTER_TABLE_INCLUDE_COLUMN_KEYWORD:
@ -2839,15 +2860,7 @@ class Generator(metaclass=_Generator):
return f"DROP{exists}{expressions}"
def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
this = self.sql(expression, "this")
expression_ = self.sql(expression, "expression")
add_constraint = f"ADD CONSTRAINT {this}" if this else "ADD"
enforced = expression.args.get("enforced")
if enforced is not None:
return f"{add_constraint} CHECK ({expression_}){' ENFORCED' if enforced else ''}"
return f"{add_constraint} {expression_}"
return f"ADD {self.expressions(expression)}"
def distinct_sql(self, expression: exp.Distinct) -> str:
this = self.expressions(expression, flat=True)
@ -3296,6 +3309,10 @@ class Generator(metaclass=_Generator):
self.unsupported("Unsupported index constraint option.")
return ""
def checkcolumnconstraint_sql(self, expression: exp.CheckColumnConstraint) -> str:
enforced = " ENFORCED" if expression.args.get("enforced") else ""
return f"CHECK ({self.sql(expression, 'this')}){enforced}"
def indexcolumnconstraint_sql(self, expression: exp.IndexColumnConstraint) -> str:
kind = self.sql(expression, "kind")
kind = f"{kind} INDEX" if kind else "INDEX"
@ -3452,9 +3469,87 @@ class Generator(metaclass=_Generator):
return expression
def _ensure_string_if_null(self, values: t.List[exp.Expression]) -> t.List[exp.Expression]:
return [
exp.func("COALESCE", exp.cast(value, "text"), exp.Literal.string(""))
for value in values
if value
]
def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
expression.set("is_end_exclusive", None)
return self.function_fallback_sql(expression)
def struct_sql(self, expression: exp.Struct) -> str:
expression.set(
"expressions",
[
exp.alias_(e.expression, e.this) if isinstance(e, exp.PropertyEQ) else e
for e in expression.expressions
],
)
return self.function_fallback_sql(expression)
def partitionrange_sql(self, expression: exp.PartitionRange) -> str:
low = self.sql(expression, "this")
high = self.sql(expression, "expression")
return f"{low} TO {high}"
def truncatetable_sql(self, expression: exp.TruncateTable) -> str:
target = "DATABASE" if expression.args.get("is_database") else "TABLE"
tables = f" {self.expressions(expression)}"
exists = " IF EXISTS" if expression.args.get("exists") else ""
on_cluster = self.sql(expression, "cluster")
on_cluster = f" {on_cluster}" if on_cluster else ""
identity = self.sql(expression, "identity")
identity = f" {identity} IDENTITY" if identity else ""
option = self.sql(expression, "option")
option = f" {option}" if option else ""
partition = self.sql(expression, "partition")
partition = f" {partition}" if partition else ""
return f"TRUNCATE {target}{exists}{tables}{on_cluster}{identity}{option}{partition}"
# This transpiles T-SQL's CONVERT function
# https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16
def convert_sql(self, expression: exp.Convert) -> str:
to = expression.this
value = expression.expression
style = expression.args.get("style")
safe = expression.args.get("safe")
strict = expression.args.get("strict")
if not to or not value:
return ""
# Retrieve length of datatype and override to default if not specified
if not seq_get(to.expressions, 0) and to.this in self.PARAMETERIZABLE_TEXT_TYPES:
to = exp.DataType.build(to.this, expressions=[exp.Literal.number(30)], nested=False)
transformed: t.Optional[exp.Expression] = None
cast = exp.Cast if strict else exp.TryCast
# Check whether a conversion with format (T-SQL calls this 'style') is applicable
if isinstance(style, exp.Literal) and style.is_int:
from sqlglot.dialects.tsql import TSQL
style_value = style.name
converted_style = TSQL.CONVERT_FORMAT_MAPPING.get(style_value)
if not converted_style:
self.unsupported(f"Unsupported T-SQL 'style' value: {style_value}")
fmt = exp.Literal.string(converted_style)
if to.this == exp.DataType.Type.DATE:
transformed = exp.StrToDate(this=value, format=fmt)
elif to.this == exp.DataType.Type.DATETIME:
transformed = exp.StrToTime(this=value, format=fmt)
elif to.this in self.PARAMETERIZABLE_TEXT_TYPES:
transformed = cast(this=exp.TimeToStr(this=value, format=fmt), to=to, safe=safe)
elif to.this == exp.DataType.Type.TEXT:
transformed = exp.TimeToStr(this=value, format=fmt)
if not transformed:
transformed = cast(this=value, to=to, safe=safe)
return self.sql(transformed)

View file

@ -53,13 +53,11 @@ def seq_get(seq: t.Sequence[T], index: int) -> t.Optional[T]:
@t.overload
def ensure_list(value: t.Collection[T]) -> t.List[T]:
...
def ensure_list(value: t.Collection[T]) -> t.List[T]: ...
@t.overload
def ensure_list(value: T) -> t.List[T]:
...
def ensure_list(value: T) -> t.List[T]: ...
def ensure_list(value):
@ -81,13 +79,11 @@ def ensure_list(value):
@t.overload
def ensure_collection(value: t.Collection[T]) -> t.Collection[T]:
...
def ensure_collection(value: t.Collection[T]) -> t.Collection[T]: ...
@t.overload
def ensure_collection(value: T) -> t.Collection[T]:
...
def ensure_collection(value: T) -> t.Collection[T]: ...
def ensure_collection(value):

View file

@ -1,16 +1,19 @@
from __future__ import annotations
import json
import logging
import typing as t
from dataclasses import dataclass, field
from sqlglot import Schema, exp, maybe_parse
from sqlglot.errors import SqlglotError
from sqlglot.optimizer import Scope, build_scope, find_all_in_scope, qualify
from sqlglot.optimizer import Scope, build_scope, find_all_in_scope, normalize_identifiers, qualify
if t.TYPE_CHECKING:
from sqlglot.dialects.dialect import DialectType
logger = logging.getLogger("sqlglot")
@dataclass(frozen=True)
class Node:
@ -18,7 +21,8 @@ class Node:
expression: exp.Expression
source: exp.Expression
downstream: t.List[Node] = field(default_factory=list)
alias: str = ""
source_name: str = ""
reference_node_name: str = ""
def walk(self) -> t.Iterator[Node]:
yield self
@ -67,7 +71,7 @@ def lineage(
column: str | exp.Column,
sql: str | exp.Expression,
schema: t.Optional[t.Dict | Schema] = None,
sources: t.Optional[t.Dict[str, str | exp.Subqueryable]] = None,
sources: t.Optional[t.Dict[str, str | exp.Query]] = None,
dialect: DialectType = None,
**kwargs,
) -> Node:
@ -86,14 +90,12 @@ def lineage(
"""
expression = maybe_parse(sql, dialect=dialect)
column = normalize_identifiers.normalize_identifiers(column, dialect=dialect).name
if sources:
expression = exp.expand(
expression,
{
k: t.cast(exp.Subqueryable, maybe_parse(v, dialect=dialect))
for k, v in sources.items()
},
{k: t.cast(exp.Query, maybe_parse(v, dialect=dialect)) for k, v in sources.items()},
dialect=dialect,
)
@ -109,14 +111,22 @@ def lineage(
if not scope:
raise SqlglotError("Cannot build lineage, sql must be SELECT")
def to_node(
if not any(select.alias_or_name == column for select in scope.expression.selects):
raise SqlglotError(f"Cannot find column '{column}' in query.")
return to_node(column, scope, dialect)
def to_node(
column: str | int,
scope: Scope,
dialect: DialectType,
scope_name: t.Optional[str] = None,
upstream: t.Optional[Node] = None,
alias: t.Optional[str] = None,
) -> Node:
aliases = {
source_name: t.Optional[str] = None,
reference_node_name: t.Optional[str] = None,
) -> Node:
source_names = {
dt.alias: dt.comments[0].split()[1]
for dt in scope.derived_tables
if dt.comments and dt.comments[0].startswith("source: ")
@ -153,7 +163,14 @@ def lineage(
raise ValueError(f"Could not find {column} in {scope.expression}")
for s in scope.union_scopes:
to_node(index, scope=s, upstream=upstream, alias=alias)
to_node(
index,
scope=s,
dialect=dialect,
upstream=upstream,
source_name=source_name,
reference_node_name=reference_node_name,
)
return upstream
@ -171,22 +188,25 @@ def lineage(
name=f"{scope_name}.{column}" if scope_name else str(column),
source=source,
expression=select,
alias=alias or "",
source_name=source_name or "",
reference_node_name=reference_node_name or "",
)
if upstream:
upstream.downstream.append(node)
subquery_scopes = {
id(subquery_scope.expression): subquery_scope
for subquery_scope in scope.subquery_scopes
id(subquery_scope.expression): subquery_scope for subquery_scope in scope.subquery_scopes
}
for subquery in find_all_in_scope(select, exp.Subqueryable):
subquery_scope = subquery_scopes[id(subquery)]
for subquery in find_all_in_scope(select, exp.UNWRAPPED_QUERIES):
subquery_scope = subquery_scopes.get(id(subquery))
if not subquery_scope:
logger.warning(f"Unknown subquery scope: {subquery.sql(dialect=dialect)}")
continue
for name in subquery.named_selects:
to_node(name, scope=subquery_scope, upstream=node)
to_node(name, scope=subquery_scope, dialect=dialect, upstream=node)
# if the select is a star add all scope sources as downstreams
if select.is_star:
@ -207,13 +227,16 @@ def lineage(
source = scope.sources.get(table)
if isinstance(source, Scope):
selected_node, _ = scope.selected_sources.get(table, (None, None))
# The table itself came from a more specific scope. Recurse into that one using the unaliased column name.
to_node(
c.name,
scope=source,
dialect=dialect,
scope_name=table,
upstream=node,
alias=aliases.get(table) or alias,
source_name=source_names.get(table) or source_name,
reference_node_name=selected_node.name if selected_node else None,
)
else:
# The source is not a scope - we've reached the end of the line. At this point, if a source is not found
@ -224,8 +247,6 @@ def lineage(
return node
return to_node(column if isinstance(column, str) else column.name, scope)
class GraphHTML:
"""Node to HTML generator using vis.js.

View file

@ -191,6 +191,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
exp.DateToDi,
exp.Floor,
exp.Levenshtein,
exp.Sign,
exp.StrPosition,
exp.TsOrDiToDi,
},
@ -262,6 +263,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
exp.DateTrunc: lambda self, e: self._annotate_timeunit(e),
exp.Distinct: lambda self, e: self._annotate_by_args(e, "expressions"),
exp.Div: lambda self, e: self._annotate_div(e),
exp.Dot: lambda self, e: self._annotate_dot(e),
exp.Explode: lambda self, e: self._annotate_explode(e),
exp.Filter: lambda self, e: self._annotate_by_args(e, "this"),
exp.If: lambda self, e: self._annotate_by_args(e, "true", "false"),
@ -273,15 +275,17 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
exp.Min: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
exp.Null: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.NULL),
exp.Nullif: lambda self, e: self._annotate_by_args(e, "this", "expression"),
exp.PropertyEQ: lambda self, e: self._annotate_by_args(e, "expression"),
exp.Slice: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
exp.Struct: lambda self, e: self._annotate_by_args(e, "expressions", struct=True),
exp.Sum: lambda self, e: self._annotate_by_args(e, "this", "expressions", promote=True),
exp.Timestamp: lambda self, e: self._annotate_with_type(
e,
exp.DataType.Type.TIMESTAMPTZ if e.args.get("with_tz") else exp.DataType.Type.TIMESTAMP,
),
exp.TryCast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
exp.Unnest: lambda self, e: self._annotate_unnest(e),
exp.VarMap: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
exp.Struct: lambda self, e: self._annotate_by_args(e, "expressions", struct=True),
}
NESTED_TYPES = {
@ -380,8 +384,11 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
source = scope.sources.get(col.table)
if isinstance(source, exp.Table):
self._set_type(col, self.schema.get_column_type(source, col))
elif source and col.table in selects and col.name in selects[col.table]:
elif source:
if col.table in selects and col.name in selects[col.table]:
self._set_type(col, selects[col.table][col.name].type)
elif isinstance(source.expression, exp.Unnest):
self._set_type(col, source.expression.type)
# Then (possibly) annotate the remaining expressions in the scope
self._maybe_annotate(scope.expression)
@ -514,7 +521,14 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
last_datatype = None
for expr in expressions:
last_datatype = self._maybe_coerce(last_datatype or expr.type, expr.type)
expr_type = expr.type
# Stop at the first nested data type found - we don't want to _maybe_coerce nested types
if expr_type.args.get("nested"):
last_datatype = expr_type
break
last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
@ -594,7 +608,26 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
return expression
def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
self._annotate_args(expression)
self._set_type(expression, None)
this_type = expression.this.type
if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
for e in this_type.expressions:
if e.name == expression.expression.name:
self._set_type(expression, e.kind)
break
return expression
def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
self._annotate_args(expression)
self._set_type(expression, seq_get(expression.this.type.expressions, 0))
return expression
def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
self._annotate_args(expression)
child = seq_get(expression.expressions, 0)
self._set_type(expression, child and seq_get(child.type.expressions, 0))
return expression

View file

@ -10,13 +10,11 @@ if t.TYPE_CHECKING:
@t.overload
def normalize_identifiers(expression: E, dialect: DialectType = None) -> E:
...
def normalize_identifiers(expression: E, dialect: DialectType = None) -> E: ...
@t.overload
def normalize_identifiers(expression: str, dialect: DialectType = None) -> exp.Identifier:
...
def normalize_identifiers(expression: str, dialect: DialectType = None) -> exp.Identifier: ...
def normalize_identifiers(expression, dialect=None):

View file

@ -120,6 +120,8 @@ def _pop_table_column_aliases(derived_tables: t.List[exp.CTE | exp.Subquery]) ->
For example, `col1` and `col2` will be dropped in SELECT ... FROM (SELECT ...) AS foo(col1, col2)
"""
for derived_table in derived_tables:
if isinstance(derived_table.parent, exp.With) and derived_table.parent.recursive:
continue
table_alias = derived_table.args.get("alias")
if table_alias:
table_alias.args.pop("columns", None)
@ -214,7 +216,13 @@ def _expand_alias_refs(scope: Scope, resolver: Resolver) -> None:
table = resolver.get_table(column.name) if resolve_table and not column.table else None
alias_expr, i = alias_to_expression.get(column.name, (None, 1))
double_agg = (
(alias_expr.find(exp.AggFunc) and column.find_ancestor(exp.AggFunc))
(
alias_expr.find(exp.AggFunc)
and (
column.find_ancestor(exp.AggFunc)
and not isinstance(column.find_ancestor(exp.Window, exp.Select), exp.Window)
)
)
if alias_expr
else False
)
@ -404,7 +412,7 @@ def _expand_stars(
tables = list(scope.selected_sources)
_add_except_columns(expression, tables, except_columns)
_add_replace_columns(expression, tables, replace_columns)
elif expression.is_star:
elif expression.is_star and not isinstance(expression, exp.Dot):
tables = [expression.table]
_add_except_columns(expression.this, tables, except_columns)
_add_replace_columns(expression.this, tables, replace_columns)
@ -437,7 +445,7 @@ def _expand_stars(
if pivot_columns:
new_selections.extend(
exp.alias_(exp.column(name, table=pivot.alias), name, copy=False)
alias(exp.column(name, table=pivot.alias), name, copy=False)
for name in pivot_columns
if name not in columns_to_exclude
)
@ -466,7 +474,7 @@ def _expand_stars(
)
# Ensures we don't overwrite the initial selections with an empty list
if new_selections:
if new_selections and isinstance(scope.expression, exp.Select):
scope.expression.set("expressions", new_selections)
@ -528,6 +536,7 @@ def qualify_outputs(scope_or_expression: Scope | exp.Expression) -> None:
new_selections.append(selection)
if isinstance(scope.expression, exp.Select):
scope.expression.set("expressions", new_selections)
@ -615,7 +624,7 @@ class Resolver:
node, _ = self.scope.selected_sources.get(table_name)
if isinstance(node, exp.Subqueryable):
if isinstance(node, exp.Query):
while node and node.alias != table_name:
node = node.parent

View file

@ -55,8 +55,8 @@ def qualify_tables(
if not table.args.get("catalog") and table.args.get("db"):
table.set("catalog", catalog)
if not isinstance(expression, exp.Subqueryable):
for node, *_ in expression.walk(prune=lambda n, *_: isinstance(n, exp.Unionable)):
if not isinstance(expression, exp.Query):
for node, *_ in expression.walk(prune=lambda n, *_: isinstance(n, exp.Query)):
if isinstance(node, exp.Table):
_qualify(node)

View file

@ -138,7 +138,7 @@ class Scope:
and _is_derived_table(node)
):
self._derived_tables.append(node)
elif isinstance(node, exp.Subqueryable):
elif isinstance(node, exp.UNWRAPPED_QUERIES):
self._subqueries.append(node)
self._collected = True
@ -225,7 +225,7 @@ class Scope:
SELECT * FROM x WHERE a IN (SELECT ...) <- that's a subquery
Returns:
list[exp.Subqueryable]: subqueries
list[exp.Select | exp.Union]: subqueries
"""
self._ensure_collected()
return self._subqueries
@ -486,8 +486,8 @@ def traverse_scope(expression: exp.Expression) -> t.List[Scope]:
Returns:
list[Scope]: scope instances
"""
if isinstance(expression, exp.Unionable) or (
isinstance(expression, exp.DDL) and isinstance(expression.expression, exp.Unionable)
if isinstance(expression, exp.Query) or (
isinstance(expression, exp.DDL) and isinstance(expression.expression, exp.Query)
):
return list(_traverse_scope(Scope(expression)))
@ -615,7 +615,7 @@ def _is_derived_table(expression: exp.Subquery) -> bool:
as it doesn't introduce a new scope. If an alias is present, it shadows all names
under the Subquery, so that's one exception to this rule.
"""
return bool(expression.alias or isinstance(expression.this, exp.Subqueryable))
return bool(expression.alias or isinstance(expression.this, exp.UNWRAPPED_QUERIES))
def _traverse_tables(scope):
@ -786,7 +786,7 @@ def walk_in_scope(expression, bfs=True, prune=None):
and _is_derived_table(node)
)
or isinstance(node, exp.UDTF)
or isinstance(node, exp.Subqueryable)
or isinstance(node, exp.UNWRAPPED_QUERIES)
):
crossed_scope_boundary = True

View file

@ -1185,7 +1185,7 @@ def gen(expression: t.Any) -> str:
GEN_MAP = {
exp.Add: lambda e: _binary(e, "+"),
exp.And: lambda e: _binary(e, "AND"),
exp.Anonymous: lambda e: f"{e.this.upper()} {','.join(gen(e) for e in e.expressions)}",
exp.Anonymous: lambda e: _anonymous(e),
exp.Between: lambda e: f"{gen(e.this)} BETWEEN {gen(e.args.get('low'))} AND {gen(e.args.get('high'))}",
exp.Boolean: lambda e: "TRUE" if e.this else "FALSE",
exp.Bracket: lambda e: f"{gen(e.this)}[{gen(e.expressions)}]",
@ -1219,6 +1219,20 @@ GEN_MAP = {
}
def _anonymous(e: exp.Anonymous) -> str:
this = e.this
if isinstance(this, str):
name = this.upper()
elif isinstance(this, exp.Identifier):
name = f'"{this.name}"' if this.quoted else this.name.upper()
else:
raise ValueError(
f"Anonymous.this expects a str or an Identifier, got '{this.__class__.__name__}'."
)
return f"{name} {','.join(gen(e) for e in e.expressions)}"
def _binary(e: exp.Binary, op: str) -> str:
return f"{gen(e.left)} {op} {gen(e.right)}"

View file

@ -94,8 +94,20 @@ def unnest(select, parent_select, next_alias_name):
else:
_replace(predicate, join_key_not_null)
group = select.args.get("group")
if group:
if {value.this} != set(group.expressions):
select = (
exp.select(exp.column(value.alias, "_q"))
.from_(select.subquery("_q", copy=False), copy=False)
.group_by(exp.column(value.alias, "_q"), copy=False)
)
else:
select = select.group_by(value.this, copy=False)
parent_select.join(
select.group_by(value.this, copy=False),
select,
on=column.eq(join_key),
join_type="LEFT",
join_alias=alias,

View file

@ -17,6 +17,8 @@ if t.TYPE_CHECKING:
logger = logging.getLogger("sqlglot")
OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
if len(args) == 1 and args[0].is_star:
@ -367,6 +369,7 @@ class Parser(metaclass=_Parser):
TokenType.TEMPORARY,
TokenType.TOP,
TokenType.TRUE,
TokenType.TRUNCATE,
TokenType.UNIQUE,
TokenType.UNPIVOT,
TokenType.UPDATE,
@ -435,6 +438,7 @@ class Parser(metaclass=_Parser):
TokenType.TABLE,
TokenType.TIMESTAMP,
TokenType.TIMESTAMPTZ,
TokenType.TRUNCATE,
TokenType.WINDOW,
TokenType.XOR,
*TYPE_TOKENS,
@ -578,7 +582,7 @@ class Parser(metaclass=_Parser):
exp.Column: lambda self: self._parse_column(),
exp.Condition: lambda self: self._parse_conjunction(),
exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
exp.Expression: lambda self: self._parse_statement(),
exp.Expression: lambda self: self._parse_expression(),
exp.From: lambda self: self._parse_from(),
exp.Group: lambda self: self._parse_group(),
exp.Having: lambda self: self._parse_having(),
@ -625,10 +629,10 @@ class Parser(metaclass=_Parser):
TokenType.SET: lambda self: self._parse_set(),
TokenType.UNCACHE: lambda self: self._parse_uncache(),
TokenType.UPDATE: lambda self: self._parse_update(),
TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
TokenType.USE: lambda self: self.expression(
exp.Use,
kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
and exp.var(self._prev.text),
kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
this=self._parse_table(schema=False),
),
}
@ -642,36 +646,44 @@ class Parser(metaclass=_Parser):
TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
}
PRIMARY_PARSERS = {
TokenType.STRING: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=True
STRING_PARSERS = {
TokenType.HEREDOC_STRING: lambda self, token: self.expression(
exp.RawString, this=token.text
),
TokenType.NUMBER: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=False
),
TokenType.STAR: lambda self, _: self.expression(
exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
),
TokenType.NULL: lambda self, _: self.expression(exp.Null),
TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
TokenType.NATIONAL_STRING: lambda self, token: self.expression(
exp.National, this=token.text
),
TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
TokenType.HEREDOC_STRING: lambda self, token: self.expression(
exp.RawString, this=token.text
TokenType.STRING: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=True
),
TokenType.UNICODE_STRING: lambda self, token: self.expression(
exp.UnicodeString,
this=token.text,
escape=self._match_text_seq("UESCAPE") and self._parse_string(),
),
}
NUMERIC_PARSERS = {
TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
TokenType.NUMBER: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=False
),
}
PRIMARY_PARSERS = {
**STRING_PARSERS,
**NUMERIC_PARSERS,
TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
TokenType.NULL: lambda self, _: self.expression(exp.Null),
TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
TokenType.STAR: lambda self, _: self.expression(
exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
),
}
PLACEHOLDER_PARSERS = {
@ -799,7 +811,9 @@ class Parser(metaclass=_Parser):
exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
),
"CHECK": lambda self: self.expression(
exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
exp.CheckColumnConstraint,
this=self._parse_wrapped(self._parse_conjunction),
enforced=self._match_text_seq("ENFORCED"),
),
"COLLATE": lambda self: self.expression(
exp.CollateColumnConstraint, this=self._parse_var()
@ -873,6 +887,8 @@ class Parser(metaclass=_Parser):
FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
FUNCTION_PARSERS = {
"CAST": lambda self: self._parse_cast(self.STRICT_CAST),
"CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
@ -895,6 +911,7 @@ class Parser(metaclass=_Parser):
QUERY_MODIFIER_PARSERS = {
TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
TokenType.WHERE: lambda self: ("where", self._parse_where()),
TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
TokenType.HAVING: lambda self: ("having", self._parse_having()),
@ -934,22 +951,23 @@ class Parser(metaclass=_Parser):
exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
}
MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
TRANSACTION_CHARACTERISTICS = {
"ISOLATION LEVEL REPEATABLE READ",
"ISOLATION LEVEL READ COMMITTED",
"ISOLATION LEVEL READ UNCOMMITTED",
"ISOLATION LEVEL SERIALIZABLE",
"READ WRITE",
"READ ONLY",
TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
"ISOLATION": (
("LEVEL", "REPEATABLE", "READ"),
("LEVEL", "READ", "COMMITTED"),
("LEVEL", "READ", "UNCOMITTED"),
("LEVEL", "SERIALIZABLE"),
),
"READ": ("WRITE", "ONLY"),
}
USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
CLONE_KEYWORDS = {"CLONE", "COPY"}
@ -1012,6 +1030,9 @@ class Parser(metaclass=_Parser):
# If this is True and '(' is not found, the keyword will be treated as an identifier
VALUES_FOLLOWED_BY_PAREN = True
# Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
SUPPORTS_IMPLICIT_UNNEST = False
__slots__ = (
"error_level",
"error_message_context",
@ -2450,10 +2471,37 @@ class Parser(metaclass=_Parser):
alias=self._parse_table_alias() if parse_alias else None,
)
def _implicit_unnests_to_explicit(self, this: E) -> E:
from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
for i, join in enumerate(this.args.get("joins") or []):
table = join.this
normalized_table = table.copy()
normalized_table.meta["maybe_column"] = True
normalized_table = _norm(normalized_table, dialect=self.dialect)
if isinstance(table, exp.Table) and not join.args.get("on"):
if normalized_table.parts[0].name in refs:
table_as_column = table.to_column()
unnest = exp.Unnest(expressions=[table_as_column])
# Table.to_column creates a parent Alias node that we want to convert to
# a TableAlias and attach to the Unnest, so it matches the parser's output
if isinstance(table.args.get("alias"), exp.TableAlias):
table_as_column.replace(table_as_column.this)
exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
table.replace(unnest)
refs.add(normalized_table.alias_or_name)
return this
def _parse_query_modifiers(
self, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]:
if isinstance(this, self.MODIFIABLES):
if isinstance(this, (exp.Query, exp.Table)):
for join in iter(self._parse_join, None):
this.append("joins", join)
for lateral in iter(self._parse_lateral, None):
@ -2478,6 +2526,10 @@ class Parser(metaclass=_Parser):
offset.set("expressions", limit_by_expressions)
continue
break
if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
this = self._implicit_unnests_to_explicit(this)
return this
def _parse_hint(self) -> t.Optional[exp.Hint]:
@ -2803,7 +2855,9 @@ class Parser(metaclass=_Parser):
or self._parse_placeholder()
)
def _parse_table_parts(self, schema: bool = False, is_db_reference: bool = False) -> exp.Table:
def _parse_table_parts(
self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
) -> exp.Table:
catalog = None
db = None
table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
@ -2817,8 +2871,20 @@ class Parser(metaclass=_Parser):
else:
catalog = db
db = table
# "" used for tsql FROM a..b case
table = self._parse_table_part(schema=schema) or ""
if (
wildcard
and self._is_connected()
and (isinstance(table, exp.Identifier) or not table)
and self._match(TokenType.STAR)
):
if isinstance(table, exp.Identifier):
table.args["this"] += "*"
else:
table = exp.Identifier(this="*")
if is_db_reference:
catalog = db
db = table
@ -2861,6 +2927,9 @@ class Parser(metaclass=_Parser):
bracket = parse_bracket and self._parse_bracket(None)
bracket = self.expression(exp.Table, this=bracket) if bracket else None
only = self._match(TokenType.ONLY)
this = t.cast(
exp.Expression,
bracket
@ -2869,6 +2938,12 @@ class Parser(metaclass=_Parser):
),
)
if only:
this.set("only", only)
# Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
self._match_text_seq("*")
if schema:
return self._parse_schema(this=this)
@ -3161,6 +3236,14 @@ class Parser(metaclass=_Parser):
def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
return [agg.alias for agg in aggregations]
def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
if not skip_where_token and not self._match(TokenType.PREWHERE):
return None
return self.expression(
exp.PreWhere, comments=self._prev_comments, this=self._parse_conjunction()
)
def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
if not skip_where_token and not self._match(TokenType.WHERE):
return None
@ -3291,8 +3374,12 @@ class Parser(metaclass=_Parser):
return None
return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
def _parse_ordered(self, parse_method: t.Optional[t.Callable] = None) -> exp.Ordered:
def _parse_ordered(
self, parse_method: t.Optional[t.Callable] = None
) -> t.Optional[exp.Ordered]:
this = parse_method() if parse_method else self._parse_conjunction()
if not this:
return None
asc = self._match(TokenType.ASC)
desc = self._match(TokenType.DESC) or (asc and False)
@ -3510,7 +3597,7 @@ class Parser(metaclass=_Parser):
if self._match_text_seq("DISTINCT", "FROM"):
klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
return self.expression(klass, this=this, expression=self._parse_conjunction())
return self.expression(klass, this=this, expression=self._parse_bitwise())
expression = self._parse_null() or self._parse_boolean()
if not expression:
@ -3528,7 +3615,7 @@ class Parser(metaclass=_Parser):
matched_l_paren = self._prev.token_type == TokenType.L_PAREN
expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
this = self.expression(exp.In, this=this, query=expressions[0])
else:
this = self.expression(exp.In, this=this, expressions=expressions)
@ -3959,7 +4046,7 @@ class Parser(metaclass=_Parser):
this = self._parse_query_modifiers(seq_get(expressions, 0))
if isinstance(this, exp.Subqueryable):
if isinstance(this, exp.UNWRAPPED_QUERIES):
this = self._parse_set_operations(
self._parse_subquery(this=this, parse_alias=False)
)
@ -4064,6 +4151,9 @@ class Parser(metaclass=_Parser):
alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
if alias:
args = self._kv_to_prop_eq(args)
if function and not anonymous:
if "dialect" in function.__code__.co_varnames:
func = function(args, dialect=self.dialect)
@ -4076,6 +4166,8 @@ class Parser(metaclass=_Parser):
this = func
else:
if token_type == TokenType.IDENTIFIER:
this = exp.Identifier(this=this, quoted=True)
this = self.expression(exp.Anonymous, this=this, expressions=args)
if isinstance(this, exp.Expression):
@ -4084,6 +4176,26 @@ class Parser(metaclass=_Parser):
self._match_r_paren(this)
return self._parse_window(this)
def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
transformed = []
for e in expressions:
if isinstance(e, self.KEY_VALUE_DEFINITIONS):
if isinstance(e, exp.Alias):
e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
if not isinstance(e, exp.PropertyEQ):
e = self.expression(
exp.PropertyEQ, this=exp.to_identifier(e.name), expression=e.expression
)
if isinstance(e.this, exp.Column):
e.this.replace(e.this.this)
transformed.append(e)
return transformed
def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
return self._parse_column_def(self._parse_id_var())
@ -4496,7 +4608,7 @@ class Parser(metaclass=_Parser):
# https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
if bracket_kind == TokenType.L_BRACE:
this = self.expression(exp.Struct, expressions=expressions)
this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
elif not this or this.name.upper() == "ARRAY":
this = self.expression(exp.Array, expressions=expressions)
else:
@ -4747,12 +4859,10 @@ class Parser(metaclass=_Parser):
return None
@t.overload
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject:
...
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
@t.overload
def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg:
...
def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
def _parse_json_object(self, agg=False):
star = self._parse_star()
@ -5140,16 +5250,16 @@ class Parser(metaclass=_Parser):
return None
def _parse_string(self) -> t.Optional[exp.Expression]:
if self._match_set((TokenType.STRING, TokenType.RAW_STRING)):
return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
if self._match_set(self.STRING_PARSERS):
return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
return self._parse_placeholder()
def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
def _parse_number(self) -> t.Optional[exp.Expression]:
if self._match(TokenType.NUMBER):
return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
if self._match_set(self.NUMERIC_PARSERS):
return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
return self._parse_placeholder()
def _parse_identifier(self) -> t.Optional[exp.Expression]:
@ -5182,6 +5292,9 @@ class Parser(metaclass=_Parser):
def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
return self._parse_var() or self._parse_string()
def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
return self._parse_primary() or self._parse_var(any_token=True)
def _parse_null(self) -> t.Optional[exp.Expression]:
if self._match_set(self.NULL_TOKENS):
return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
@ -5200,16 +5313,12 @@ class Parser(metaclass=_Parser):
return self._parse_placeholder()
def _parse_parameter(self) -> exp.Parameter:
def _parse_parameter_part() -> t.Optional[exp.Expression]:
return (
self._parse_identifier() or self._parse_primary() or self._parse_var(any_token=True)
)
self._match(TokenType.L_BRACE)
this = _parse_parameter_part()
expression = self._match(TokenType.COLON) and _parse_parameter_part()
this = self._parse_identifier() or self._parse_primary_or_var()
expression = self._match(TokenType.COLON) and (
self._parse_identifier() or self._parse_primary_or_var()
)
self._match(TokenType.R_BRACE)
return self.expression(exp.Parameter, this=this, expression=expression)
def _parse_placeholder(self) -> t.Optional[exp.Expression]:
@ -5376,35 +5485,15 @@ class Parser(metaclass=_Parser):
exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
)
def _parse_add_constraint(self) -> exp.AddConstraint:
this = None
kind = self._prev.token_type
if kind == TokenType.CONSTRAINT:
this = self._parse_id_var()
if self._match_text_seq("CHECK"):
expression = self._parse_wrapped(self._parse_conjunction)
enforced = self._match_text_seq("ENFORCED") or False
return self.expression(
exp.AddConstraint, this=this, expression=expression, enforced=enforced
)
if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
expression = self._parse_foreign_key()
elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
expression = self._parse_primary_key()
else:
expression = None
return self.expression(exp.AddConstraint, this=this, expression=expression)
def _parse_alter_table_add(self) -> t.List[exp.Expression]:
index = self._index - 1
if self._match_set(self.ADD_CONSTRAINT_TOKENS):
return self._parse_csv(self._parse_add_constraint)
if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
return self._parse_csv(
lambda: self.expression(
exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
)
)
self._retreat(index)
if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
@ -5472,6 +5561,7 @@ class Parser(metaclass=_Parser):
parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
if parser:
actions = ensure_list(parser(self))
options = self._parse_csv(self._parse_property)
if not self._curr and actions:
return self.expression(
@ -5480,6 +5570,7 @@ class Parser(metaclass=_Parser):
exists=exists,
actions=actions,
only=only,
options=options,
)
return self._parse_as_command(start)
@ -5610,12 +5701,35 @@ class Parser(metaclass=_Parser):
return set_
def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
for option in options:
if self._match_text_seq(*option.split(" ")):
return exp.var(option)
def _parse_var_from_options(
self, options: OPTIONS_TYPE, raise_unmatched: bool = True
) -> t.Optional[exp.Var]:
start = self._curr
if not start:
return None
option = start.text.upper()
continuations = options.get(option)
index = self._index
self._advance()
for keywords in continuations or []:
if isinstance(keywords, str):
keywords = (keywords,)
if self._match_text_seq(*keywords):
option = f"{option} {' '.join(keywords)}"
break
else:
if continuations or continuations is None:
if raise_unmatched:
self.raise_error(f"Unknown option {option}")
self._retreat(index)
return None
return exp.var(option)
def _parse_as_command(self, start: Token) -> exp.Command:
while self._curr:
self._advance()
@ -5806,14 +5920,12 @@ class Parser(metaclass=_Parser):
return True
@t.overload
def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
...
def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression: ...
@t.overload
def _replace_columns_with_dots(
self, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]:
...
) -> t.Optional[exp.Expression]: ...
def _replace_columns_with_dots(self, this):
if isinstance(this, exp.Dot):
@ -5849,3 +5961,53 @@ class Parser(metaclass=_Parser):
else:
column.replace(dot_or_id)
return node
def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
start = self._prev
# Not to be confused with TRUNCATE(number, decimals) function call
if self._match(TokenType.L_PAREN):
self._retreat(self._index - 2)
return self._parse_function()
# Clickhouse supports TRUNCATE DATABASE as well
is_database = self._match(TokenType.DATABASE)
self._match(TokenType.TABLE)
exists = self._parse_exists(not_=False)
expressions = self._parse_csv(
lambda: self._parse_table(schema=True, is_db_reference=is_database)
)
cluster = self._parse_on_property() if self._match(TokenType.ON) else None
if self._match_text_seq("RESTART", "IDENTITY"):
identity = "RESTART"
elif self._match_text_seq("CONTINUE", "IDENTITY"):
identity = "CONTINUE"
else:
identity = None
if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
option = self._prev.text
else:
option = None
partition = self._parse_partition()
# Fallback case
if self._curr:
return self._parse_as_command(start)
return self.expression(
exp.TruncateTable,
expressions=expressions,
is_database=is_database,
exists=exists,
cluster=cluster,
identity=identity,
option=option,
partition=partition,
)

View file

@ -302,6 +302,7 @@ class TokenType(AutoName):
OBJECT_IDENTIFIER = auto()
OFFSET = auto()
ON = auto()
ONLY = auto()
OPERATOR = auto()
ORDER_BY = auto()
ORDER_SIBLINGS_BY = auto()
@ -317,6 +318,7 @@ class TokenType(AutoName):
PIVOT = auto()
PLACEHOLDER = auto()
PRAGMA = auto()
PREWHERE = auto()
PRIMARY_KEY = auto()
PROCEDURE = auto()
PROPERTIES = auto()
@ -353,6 +355,7 @@ class TokenType(AutoName):
TOP = auto()
THEN = auto()
TRUE = auto()
TRUNCATE = auto()
UNCACHE = auto()
UNION = auto()
UNNEST = auto()
@ -370,6 +373,7 @@ class TokenType(AutoName):
UNIQUE = auto()
VERSION_SNAPSHOT = auto()
TIMESTAMP_SNAPSHOT = auto()
OPTION = auto()
_ALL_TOKEN_TYPES = list(TokenType)
@ -657,6 +661,7 @@ class Tokenizer(metaclass=_Tokenizer):
"DROP": TokenType.DROP,
"ELSE": TokenType.ELSE,
"END": TokenType.END,
"ENUM": TokenType.ENUM,
"ESCAPE": TokenType.ESCAPE,
"EXCEPT": TokenType.EXCEPT,
"EXECUTE": TokenType.EXECUTE,
@ -752,6 +757,7 @@ class Tokenizer(metaclass=_Tokenizer):
"TEMPORARY": TokenType.TEMPORARY,
"THEN": TokenType.THEN,
"TRUE": TokenType.TRUE,
"TRUNCATE": TokenType.TRUNCATE,
"UNION": TokenType.UNION,
"UNKNOWN": TokenType.UNKNOWN,
"UNNEST": TokenType.UNNEST,
@ -860,7 +866,6 @@ class Tokenizer(metaclass=_Tokenizer):
"GRANT": TokenType.COMMAND,
"OPTIMIZE": TokenType.COMMAND,
"PREPARE": TokenType.COMMAND,
"TRUNCATE": TokenType.COMMAND,
"VACUUM": TokenType.COMMAND,
"USER-DEFINED": TokenType.USERDEFINED,
"FOR VERSION": TokenType.VERSION_SNAPSHOT,
@ -1036,12 +1041,6 @@ class Tokenizer(metaclass=_Tokenizer):
def _text(self) -> str:
return self.sql[self._start : self._current]
def peek(self, i: int = 0) -> str:
i = self._current + i
if i < self.size:
return self.sql[i]
return ""
def _add(self, token_type: TokenType, text: t.Optional[str] = None) -> None:
self._prev_token_line = self._line
@ -1182,12 +1181,8 @@ class Tokenizer(metaclass=_Tokenizer):
if self._peek.isdigit():
self._advance()
elif self._peek == "." and not decimal:
after = self.peek(1)
if after.isdigit() or not after.isalpha():
decimal = True
self._advance()
else:
return self._add(TokenType.VAR)
elif self._peek in ("-", "+") and scientific == 1:
scientific += 1
self._advance()

View file

@ -547,7 +547,7 @@ def move_partitioned_by_to_schema_columns(expression: exp.Expression) -> exp.Exp
prop
and prop.this
and isinstance(prop.this, exp.Schema)
and all(isinstance(e, exp.ColumnDef) and e.args.get("kind") for e in prop.this.expressions)
and all(isinstance(e, exp.ColumnDef) and e.kind for e in prop.this.expressions)
):
prop_this = exp.Tuple(
expressions=[exp.to_identifier(e.this) for e in prop.this.expressions]
@ -560,6 +560,22 @@ def move_partitioned_by_to_schema_columns(expression: exp.Expression) -> exp.Exp
return expression
def struct_kv_to_alias(expression: exp.Expression) -> exp.Expression:
"""
Convert struct arguments to aliases: STRUCT(1 AS y) .
"""
if isinstance(expression, exp.Struct):
expression.set(
"expressions",
[
exp.alias_(e.expression, e.this) if isinstance(e, exp.PropertyEQ) else e
for e in expression.expressions
],
)
return expression
def preprocess(
transforms: t.List[t.Callable[[exp.Expression], exp.Expression]],
) -> t.Callable[[Generator, exp.Expression], str]:

2
sqlglotrs/Cargo.lock generated
View file

@ -188,7 +188,7 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "sqlglotrs"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"pyo3",
]

View file

@ -1,6 +1,6 @@
[package]
name = "sqlglotrs"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
[lib]

View file

@ -178,15 +178,6 @@ impl<'a> TokenizerState<'a> {
Ok(())
}
fn peek(&self, i: usize) -> Result<char, TokenizerError> {
let index = self.current + i;
if index < self.size {
self.char_at(index)
} else {
Ok('\0')
}
}
fn chars(&self, size: usize) -> String {
let start = self.current - 1;
let end = start + size;
@ -469,13 +460,8 @@ impl<'a> TokenizerState<'a> {
if self.peek_char.is_digit(10) {
self.advance(1)?;
} else if self.peek_char == '.' && !decimal {
let after = self.peek(1)?;
if after.is_digit(10) || !after.is_alphabetic() {
decimal = true;
self.advance(1)?;
} else {
return self.add(self.token_types.var, None);
}
} else if (self.peek_char == '-' || self.peek_char == '+') && scientific == 1 {
scientific += 1;
self.advance(1)?;

View file

@ -280,9 +280,9 @@ class TestFunctions(unittest.TestCase):
def test_signum(self):
col_str = SF.signum("cola")
self.assertEqual("SIGNUM(cola)", col_str.sql())
self.assertEqual("SIGN(cola)", col_str.sql())
col = SF.signum(SF.col("cola"))
self.assertEqual("SIGNUM(cola)", col.sql())
self.assertEqual("SIGN(cola)", col.sql())
def test_sin(self):
col_str = SF.sin("cola")

View file

@ -5,7 +5,9 @@ from sqlglot import (
ParseError,
TokenError,
UnsupportedError,
exp,
parse,
parse_one,
transpile,
)
from sqlglot.helper import logger as helper_logger
@ -18,6 +20,51 @@ class TestBigQuery(Validator):
maxDiff = None
def test_bigquery(self):
self.validate_all(
"SELECT STRUCT(1, 2, 3), STRUCT(), STRUCT('abc'), STRUCT(1, t.str_col), STRUCT(1 as a, 'abc' AS b), STRUCT(str_col AS abc)",
write={
"bigquery": "SELECT STRUCT(1, 2, 3), STRUCT(), STRUCT('abc'), STRUCT(1, t.str_col), STRUCT(1 AS a, 'abc' AS b), STRUCT(str_col AS abc)",
"duckdb": "SELECT {'_0': 1, '_1': 2, '_2': 3}, {}, {'_0': 'abc'}, {'_0': 1, '_1': t.str_col}, {'a': 1, 'b': 'abc'}, {'abc': str_col}",
"hive": "SELECT STRUCT(1, 2, 3), STRUCT(), STRUCT('abc'), STRUCT(1, t.str_col), STRUCT(1, 'abc'), STRUCT(str_col)",
"spark2": "SELECT STRUCT(1, 2, 3), STRUCT(), STRUCT('abc'), STRUCT(1, t.str_col), STRUCT(1 AS a, 'abc' AS b), STRUCT(str_col AS abc)",
"spark": "SELECT STRUCT(1, 2, 3), STRUCT(), STRUCT('abc'), STRUCT(1, t.str_col), STRUCT(1 AS a, 'abc' AS b), STRUCT(str_col AS abc)",
"snowflake": "SELECT OBJECT_CONSTRUCT('_0', 1, '_1', 2, '_2', 3), OBJECT_CONSTRUCT(), OBJECT_CONSTRUCT('_0', 'abc'), OBJECT_CONSTRUCT('_0', 1, '_1', t.str_col), OBJECT_CONSTRUCT('a', 1, 'b', 'abc'), OBJECT_CONSTRUCT('abc', str_col)",
# fallback to unnamed without type inference
"trino": "SELECT ROW(1, 2, 3), ROW(), ROW('abc'), ROW(1, t.str_col), CAST(ROW(1, 'abc') AS ROW(a INTEGER, b VARCHAR)), ROW(str_col)",
},
)
self.validate_all(
"PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E6S%z', x)",
write={
"bigquery": "PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E6S%z', x)",
"duckdb": "STRPTIME(x, '%Y-%m-%dT%H:%M:%S.%f%z')",
},
)
table = parse_one("x-0._y.z", dialect="bigquery", into=exp.Table)
self.assertEqual(table.catalog, "x-0")
self.assertEqual(table.db, "_y")
self.assertEqual(table.name, "z")
table = parse_one("x-0._y", dialect="bigquery", into=exp.Table)
self.assertEqual(table.db, "x-0")
self.assertEqual(table.name, "_y")
self.validate_identity("SELECT * FROM x-0.y")
self.assertEqual(exp.to_table("`x.y.z`", dialect="bigquery").sql(), '"x"."y"."z"')
self.assertEqual(exp.to_table("`x.y.z`", dialect="bigquery").sql("bigquery"), "`x.y.z`")
self.assertEqual(exp.to_table("`x`.`y`", dialect="bigquery").sql("bigquery"), "`x`.`y`")
select_with_quoted_udf = self.validate_identity("SELECT `p.d.UdF`(data) FROM `p.d.t`")
self.assertEqual(select_with_quoted_udf.selects[0].name, "p.d.UdF")
self.validate_identity("SELECT `p.d.UdF`(data).* FROM `p.d.t`")
self.validate_identity("SELECT * FROM `my-project.my-dataset.my-table`")
self.validate_identity("CREATE OR REPLACE TABLE `a.b.c` CLONE `a.b.d`")
self.validate_identity("SELECT x, 1 AS y GROUP BY 1 ORDER BY 1")
self.validate_identity("SELECT * FROM x.*")
self.validate_identity("SELECT * FROM x.y*")
self.validate_identity("CASE A WHEN 90 THEN 'red' WHEN 50 THEN 'blue' ELSE 'green' END")
self.validate_identity("CREATE SCHEMA x DEFAULT COLLATE 'en'")
self.validate_identity("CREATE TABLE x (y INT64) DEFAULT COLLATE 'en'")
self.validate_identity("PARSE_JSON('{}', wide_number_mode => 'exact')")
@ -90,6 +137,16 @@ class TestBigQuery(Validator):
self.validate_identity("LOG(n, b)")
self.validate_identity("SELECT COUNT(x RESPECT NULLS)")
self.validate_identity("SELECT LAST_VALUE(x IGNORE NULLS) OVER y AS x")
self.validate_identity("SELECT ARRAY((SELECT AS STRUCT 1 AS a, 2 AS b))")
self.validate_identity("SELECT ARRAY((SELECT AS STRUCT 1 AS a, 2 AS b) LIMIT 10)")
self.validate_identity("CAST(x AS CHAR)", "CAST(x AS STRING)")
self.validate_identity("CAST(x AS NCHAR)", "CAST(x AS STRING)")
self.validate_identity("CAST(x AS NVARCHAR)", "CAST(x AS STRING)")
self.validate_identity("CAST(x AS TIMESTAMPTZ)", "CAST(x AS TIMESTAMP)")
self.validate_identity("CAST(x AS RECORD)", "CAST(x AS STRUCT)")
self.validate_identity(
"SELECT * FROM `SOME_PROJECT_ID.SOME_DATASET_ID.INFORMATION_SCHEMA.SOME_VIEW`"
)
self.validate_identity(
"SELECT * FROM test QUALIFY a IS DISTINCT FROM b WINDOW c AS (PARTITION BY d)"
)
@ -120,6 +177,10 @@ class TestBigQuery(Validator):
self.validate_identity(
"""SELECT JSON_EXTRACT_SCALAR('5')""", """SELECT JSON_EXTRACT_SCALAR('5', '$')"""
)
self.validate_identity(
"SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)",
"SELECT ARRAY(SELECT AS STRUCT 1 AS a, 2 AS b)",
)
self.validate_identity(
"select array_contains([1, 2, 3], 1)",
"SELECT EXISTS(SELECT 1 FROM UNNEST([1, 2, 3]) AS _col WHERE _col = 1)",
@ -168,10 +229,6 @@ class TestBigQuery(Validator):
"""SELECT JSON '"foo"' AS json_data""",
"""SELECT PARSE_JSON('"foo"') AS json_data""",
)
self.validate_identity(
"CREATE OR REPLACE TABLE `a.b.c` CLONE `a.b.d`",
"CREATE OR REPLACE TABLE a.b.c CLONE a.b.d",
)
self.validate_identity(
"SELECT * FROM UNNEST(x) WITH OFFSET EXCEPT DISTINCT SELECT * FROM UNNEST(y) WITH OFFSET",
"SELECT * FROM UNNEST(x) WITH OFFSET AS offset EXCEPT DISTINCT SELECT * FROM UNNEST(y) WITH OFFSET AS offset",
@ -185,6 +242,39 @@ class TestBigQuery(Validator):
r"REGEXP_EXTRACT(svc_plugin_output, '\\\\\\((.*)')",
)
self.validate_all(
"PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E6S%z', x)",
write={
"bigquery": "PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E6S%z', x)",
"duckdb": "STRPTIME(x, '%Y-%m-%dT%H:%M:%S.%f%z')",
},
)
self.validate_all(
"SELECT results FROM Coordinates, Coordinates.position AS results",
write={
"bigquery": "SELECT results FROM Coordinates, UNNEST(Coordinates.position) AS results",
"presto": "SELECT results FROM Coordinates, UNNEST(Coordinates.position) AS _t(results)",
},
)
self.validate_all(
"SELECT results FROM Coordinates, `Coordinates.position` AS results",
write={
"bigquery": "SELECT results FROM Coordinates, `Coordinates.position` AS results",
"presto": 'SELECT results FROM Coordinates, "Coordinates"."position" AS results',
},
)
self.validate_all(
"SELECT results FROM Coordinates AS c, UNNEST(c.position) AS results",
read={
"presto": "SELECT results FROM Coordinates AS c, UNNEST(c.position) AS _t(results)",
"redshift": "SELECT results FROM Coordinates AS c, c.position AS results",
},
write={
"bigquery": "SELECT results FROM Coordinates AS c, UNNEST(c.position) AS results",
"presto": "SELECT results FROM Coordinates AS c, UNNEST(c.position) AS _t(results)",
"redshift": "SELECT results FROM Coordinates AS c, c.position AS results",
},
)
self.validate_all(
"TIMESTAMP(x)",
write={
@ -434,8 +524,8 @@ class TestBigQuery(Validator):
self.validate_all(
"CREATE OR REPLACE TABLE `a.b.c` COPY `a.b.d`",
write={
"bigquery": "CREATE OR REPLACE TABLE a.b.c COPY a.b.d",
"snowflake": "CREATE OR REPLACE TABLE a.b.c CLONE a.b.d",
"bigquery": "CREATE OR REPLACE TABLE `a.b.c` COPY `a.b.d`",
"snowflake": 'CREATE OR REPLACE TABLE "a"."b"."c" CLONE "a"."b"."d"',
},
)
(
@ -475,11 +565,6 @@ class TestBigQuery(Validator):
),
)
self.validate_all("LEAST(x, y)", read={"sqlite": "MIN(x, y)"})
self.validate_all("CAST(x AS CHAR)", write={"bigquery": "CAST(x AS STRING)"})
self.validate_all("CAST(x AS NCHAR)", write={"bigquery": "CAST(x AS STRING)"})
self.validate_all("CAST(x AS NVARCHAR)", write={"bigquery": "CAST(x AS STRING)"})
self.validate_all("CAST(x AS TIMESTAMPTZ)", write={"bigquery": "CAST(x AS TIMESTAMP)"})
self.validate_all("CAST(x AS RECORD)", write={"bigquery": "CAST(x AS STRUCT)"})
self.validate_all(
'SELECT TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE)',
write={
@ -566,11 +651,11 @@ class TestBigQuery(Validator):
read={"spark": "select posexplode_outer([])"},
)
self.validate_all(
"SELECT AS STRUCT ARRAY(SELECT AS STRUCT b FROM x) AS y FROM z",
"SELECT AS STRUCT ARRAY(SELECT AS STRUCT 1 AS b FROM x) AS y FROM z",
write={
"": "SELECT AS STRUCT ARRAY(SELECT AS STRUCT b FROM x) AS y FROM z",
"bigquery": "SELECT AS STRUCT ARRAY(SELECT AS STRUCT b FROM x) AS y FROM z",
"duckdb": "SELECT {'y': ARRAY(SELECT {'b': b} FROM x)} FROM z",
"": "SELECT AS STRUCT ARRAY(SELECT AS STRUCT 1 AS b FROM x) AS y FROM z",
"bigquery": "SELECT AS STRUCT ARRAY(SELECT AS STRUCT 1 AS b FROM x) AS y FROM z",
"duckdb": "SELECT {'y': ARRAY(SELECT {'b': 1} FROM x)} FROM z",
},
)
self.validate_all(
@ -585,25 +670,9 @@ class TestBigQuery(Validator):
"bigquery": "PARSE_TIMESTAMP('%Y.%m.%d %I:%M:%S%z', x)",
},
)
self.validate_all(
self.validate_identity(
"CREATE TEMP TABLE foo AS SELECT 1",
write={"bigquery": "CREATE TEMPORARY TABLE foo AS SELECT 1"},
)
self.validate_all(
"SELECT * FROM `SOME_PROJECT_ID.SOME_DATASET_ID.INFORMATION_SCHEMA.SOME_VIEW`",
write={
"bigquery": "SELECT * FROM SOME_PROJECT_ID.SOME_DATASET_ID.INFORMATION_SCHEMA.SOME_VIEW",
},
)
self.validate_all(
"SELECT * FROM `my-project.my-dataset.my-table`",
write={"bigquery": "SELECT * FROM `my-project`.`my-dataset`.`my-table`"},
)
self.validate_all(
"SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)",
write={
"bigquery": "SELECT ARRAY(SELECT AS STRUCT 1 AS a, 2 AS b)",
},
"CREATE TEMPORARY TABLE foo AS SELECT 1",
)
self.validate_all(
"REGEXP_CONTAINS('foo', '.*')",
@ -1088,6 +1157,35 @@ WHERE
self.assertIn("unsupported syntax", cm.output[0])
with self.assertLogs(helper_logger):
statements = parse(
"""
BEGIN
DECLARE MY_VAR INT64 DEFAULT 1;
SET MY_VAR = (SELECT 0);
IF MY_VAR = 1 THEN SELECT 'TRUE';
ELSEIF MY_VAR = 0 THEN SELECT 'FALSE';
ELSE SELECT 'NULL';
END IF;
END
""",
read="bigquery",
)
expected_statements = (
"BEGIN DECLARE MY_VAR INT64 DEFAULT 1",
"SET MY_VAR = (SELECT 0)",
"IF MY_VAR = 1 THEN SELECT 'TRUE'",
"ELSEIF MY_VAR = 0 THEN SELECT 'FALSE'",
"ELSE SELECT 'NULL'",
"END IF",
"END",
)
for actual, expected in zip(statements, expected_statements):
self.assertEqual(actual.sql(dialect="bigquery"), expected)
with self.assertLogs(helper_logger) as cm:
self.validate_identity(
"SELECT * FROM t AS t(c1, c2)",

View file

@ -6,6 +6,21 @@ class TestClickhouse(Validator):
dialect = "clickhouse"
def test_clickhouse(self):
self.validate_all(
"SELECT * FROM x PREWHERE y = 1 WHERE z = 2",
write={
"": "SELECT * FROM x WHERE z = 2",
"clickhouse": "SELECT * FROM x PREWHERE y = 1 WHERE z = 2",
},
)
self.validate_all(
"SELECT * FROM x AS prewhere",
read={
"clickhouse": "SELECT * FROM x AS prewhere",
"duckdb": "SELECT * FROM x prewhere",
},
)
self.validate_identity("SELECT * FROM x LIMIT 1 UNION ALL SELECT * FROM y")
string_types = [
@ -77,6 +92,7 @@ class TestClickhouse(Validator):
self.validate_identity("""SELECT JSONExtractString('{"x": {"y": 1}}', 'x', 'y')""")
self.validate_identity("SELECT * FROM table LIMIT 1 BY a, b")
self.validate_identity("SELECT * FROM table LIMIT 2 OFFSET 1 BY a, b")
self.validate_identity(
"SELECT $1$foo$1$",
"SELECT 'foo'",
@ -134,6 +150,9 @@ class TestClickhouse(Validator):
self.validate_identity(
"CREATE MATERIALIZED VIEW test_view (id UInt8) TO db.table1 AS SELECT * FROM test_data"
)
self.validate_identity("TRUNCATE TABLE t1 ON CLUSTER test_cluster")
self.validate_identity("TRUNCATE DATABASE db")
self.validate_identity("TRUNCATE DATABASE db ON CLUSTER test_cluster")
self.validate_all(
"SELECT arrayJoin([1,2,3])",
@ -373,6 +392,7 @@ class TestClickhouse(Validator):
def test_cte(self):
self.validate_identity("WITH 'x' AS foo SELECT foo")
self.validate_identity("WITH ['c'] AS field_names SELECT field_names")
self.validate_identity("WITH SUM(bytes) AS foo SELECT foo FROM system.parts")
self.validate_identity("WITH (SELECT foo) AS bar SELECT bar + 5")
self.validate_identity("WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT * FROM test1")

View file

@ -38,6 +38,11 @@ class TestDatabricks(Validator):
"CREATE FUNCTION add_one(x INT) RETURNS INT LANGUAGE PYTHON AS $FOO$def add_one(x):\n return x+1$FOO$"
)
self.validate_identity("TRUNCATE TABLE t1 PARTITION(age = 10, name = 'test', address)")
self.validate_identity(
"TRUNCATE TABLE t1 PARTITION(age = 10, name = 'test', city LIKE 'LA')"
)
self.validate_all(
"CREATE TABLE foo (x INT GENERATED ALWAYS AS (YEAR(y)))",
write={

View file

@ -1108,6 +1108,11 @@ class TestDialect(Validator):
)
def test_order_by(self):
self.validate_identity(
"SELECT c FROM t ORDER BY a, b,",
"SELECT c FROM t ORDER BY a, b",
)
self.validate_all(
"SELECT fname, lname, age FROM person ORDER BY age DESC NULLS FIRST, fname ASC NULLS LAST, lname",
write={
@ -1777,7 +1782,7 @@ class TestDialect(Validator):
"CREATE TABLE t (c CHAR, nc NCHAR, v1 VARCHAR, v2 VARCHAR2, nv NVARCHAR, nv2 NVARCHAR2)",
write={
"duckdb": "CREATE TABLE t (c TEXT, nc TEXT, v1 TEXT, v2 TEXT, nv TEXT, nv2 TEXT)",
"hive": "CREATE TABLE t (c CHAR, nc CHAR, v1 STRING, v2 STRING, nv STRING, nv2 STRING)",
"hive": "CREATE TABLE t (c STRING, nc STRING, v1 STRING, v2 STRING, nv STRING, nv2 STRING)",
"oracle": "CREATE TABLE t (c CHAR, nc NCHAR, v1 VARCHAR2, v2 VARCHAR2, nv NVARCHAR2, nv2 NVARCHAR2)",
"postgres": "CREATE TABLE t (c CHAR, nc CHAR, v1 VARCHAR, v2 VARCHAR, nv VARCHAR, nv2 VARCHAR)",
"sqlite": "CREATE TABLE t (c TEXT, nc TEXT, v1 TEXT, v2 TEXT, nv TEXT, nv2 TEXT)",
@ -2301,3 +2306,9 @@ SELECT
"tsql": UnsupportedError,
},
)
def test_truncate(self):
self.validate_identity("TRUNCATE TABLE table")
self.validate_identity("TRUNCATE TABLE db.schema.test")
self.validate_identity("TRUNCATE TABLE IF EXISTS db.schema.test")
self.validate_identity("TRUNCATE TABLE t1, t2, t3")

View file

@ -26,6 +26,16 @@ class TestDoris(Validator):
"doris": "SELECT ARRAY_SUM(x -> x * x, ARRAY(2, 3))",
},
)
self.validate_all(
"MONTHS_ADD(d, n)",
read={
"oracle": "ADD_MONTHS(d, n)",
},
write={
"doris": "MONTHS_ADD(d, n)",
"oracle": "ADD_MONTHS(d, n)",
},
)
def test_identity(self):
self.validate_identity("COALECSE(a, b, c, d)")

View file

@ -7,9 +7,14 @@ class TestDuckDB(Validator):
dialect = "duckdb"
def test_duckdb(self):
struct_pack = parse_one('STRUCT_PACK("a b" := 1)', read="duckdb")
self.assertIsInstance(struct_pack.expressions[0].this, exp.Identifier)
self.assertEqual(struct_pack.sql(dialect="duckdb"), "{'a b': 1}")
self.validate_all(
'STRUCT_PACK("a b" := 1)',
write={
"duckdb": "{'a b': 1}",
"spark": "STRUCT(1 AS `a b`)",
"snowflake": "OBJECT_CONSTRUCT('a b', 1)",
},
)
self.validate_all(
"SELECT SUM(X) OVER (ORDER BY x)",
@ -52,8 +57,21 @@ class TestDuckDB(Validator):
exp.select("*").from_("t").offset(exp.select("5").subquery()).sql(dialect="duckdb"),
)
for struct_value in ("{'a': 1}", "struct_pack(a := 1)"):
self.validate_all(struct_value, write={"presto": UnsupportedError})
self.validate_all(
"{'a': 1, 'b': '2'}", write={"presto": "CAST(ROW(1, '2') AS ROW(a INTEGER, b VARCHAR))"}
)
self.validate_all(
"struct_pack(a := 1, b := 2)",
write={"presto": "CAST(ROW(1, 2) AS ROW(a INTEGER, b INTEGER))"},
)
self.validate_all(
"struct_pack(a := 1, b := x)",
write={
"duckdb": "{'a': 1, 'b': x}",
"presto": UnsupportedError,
},
)
for join_type in ("SEMI", "ANTI"):
exists = "EXISTS" if join_type == "SEMI" else "NOT EXISTS"
@ -171,7 +189,6 @@ class TestDuckDB(Validator):
},
)
self.validate_identity("SELECT i FROM RANGE(5) AS _(i) ORDER BY i ASC")
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)")
@ -209,6 +226,10 @@ class TestDuckDB(Validator):
self.validate_identity("FROM (FROM tbl)", "SELECT * FROM (SELECT * FROM tbl)")
self.validate_identity("FROM tbl", "SELECT * FROM tbl")
self.validate_identity("x -> '$.family'")
self.validate_identity("CREATE TABLE color (name ENUM('RED', 'GREEN', 'BLUE'))")
self.validate_identity(
"SELECT * FROM x LEFT JOIN UNNEST(y)", "SELECT * FROM x LEFT JOIN UNNEST(y) ON TRUE"
)
self.validate_identity(
"""SELECT '{"foo": [1, 2, 3]}' -> 'foo' -> 0""",
"""SELECT '{"foo": [1, 2, 3]}' -> '$.foo' -> '$[0]'""",
@ -623,6 +644,27 @@ class TestDuckDB(Validator):
},
)
self.validate_identity("SELECT * FROM RANGE(1, 5, 10)")
self.validate_identity("SELECT * FROM GENERATE_SERIES(2, 13, 4)")
self.validate_all(
"WITH t AS (SELECT i, i * i * i * i * i AS i5 FROM RANGE(1, 5) t(i)) SELECT * FROM t",
write={
"duckdb": "WITH t AS (SELECT i, i * i * i * i * i AS i5 FROM RANGE(1, 5) AS t(i)) SELECT * FROM t",
"sqlite": "WITH t AS (SELECT i, i * i * i * i * i AS i5 FROM (SELECT value AS i FROM GENERATE_SERIES(1, 5)) AS t) SELECT * FROM t",
},
)
self.validate_identity(
"""SELECT i FROM RANGE(5) AS _(i) ORDER BY i ASC""",
"""SELECT i FROM RANGE(0, 5) AS _(i) ORDER BY i ASC""",
)
self.validate_identity(
"""SELECT i FROM GENERATE_SERIES(12) AS _(i) ORDER BY i ASC""",
"""SELECT i FROM GENERATE_SERIES(0, 12) AS _(i) ORDER BY i ASC""",
)
def test_array_index(self):
with self.assertLogs(helper_logger) as cm:
self.validate_all(
@ -994,3 +1036,10 @@ class TestDuckDB(Validator):
read={"bigquery": "IS_INF(x)"},
write={"bigquery": "IS_INF(x)", "duckdb": "ISINF(x)"},
)
def test_parameter_token(self):
self.validate_all(
"SELECT $foo",
read={"bigquery": "SELECT @foo"},
write={"bigquery": "SELECT @foo", "duckdb": "SELECT $foo"},
)

View file

@ -440,6 +440,9 @@ class TestHive(Validator):
self.validate_identity(
"SELECT key, value, GROUPING__ID, COUNT(*) FROM T1 GROUP BY key, value WITH ROLLUP"
)
self.validate_identity(
"TRUNCATE TABLE t1 PARTITION(age = 10, name = 'test', address = 'abc')"
)
self.validate_all(
"SELECT ${hiveconf:some_var}",
@ -611,12 +614,6 @@ class TestHive(Validator):
"spark": "GET_JSON_OBJECT(x, '$.name')",
},
)
self.validate_all(
"STRUCT(a = b, c = d)",
read={
"snowflake": "OBJECT_CONSTRUCT(a, b, c, d)",
},
)
self.validate_all(
"MAP(a, b, c, d)",
read={

View file

@ -29,6 +29,7 @@ class TestMySQL(Validator):
self.validate_identity("CREATE TABLE foo (a BIGINT, INDEX USING BTREE (b))")
self.validate_identity("CREATE TABLE foo (a BIGINT, FULLTEXT INDEX (b))")
self.validate_identity("CREATE TABLE foo (a BIGINT, SPATIAL INDEX (b))")
self.validate_identity("ALTER TABLE t1 ADD COLUMN x INT, ALGORITHM=INPLACE, LOCK=EXCLUSIVE")
self.validate_identity(
"CREATE TABLE `oauth_consumer` (`key` VARCHAR(32) NOT NULL, UNIQUE `OAUTH_CONSUMER_KEY` (`key`))"
)
@ -68,6 +69,26 @@ class TestMySQL(Validator):
self.validate_identity(
"CREATE OR REPLACE VIEW my_view AS SELECT column1 AS `boo`, column2 AS `foo` FROM my_table WHERE column3 = 'some_value' UNION SELECT q.* FROM fruits_table, JSON_TABLE(Fruits, '$[*]' COLUMNS(id VARCHAR(255) PATH '$.$id', value VARCHAR(255) PATH '$.value')) AS q",
)
self.validate_identity(
"CREATE TABLE `foo` (`id` char(36) NOT NULL DEFAULT (uuid()), PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`))",
"CREATE TABLE `foo` (`id` CHAR(36) NOT NULL DEFAULT (UUID()), PRIMARY KEY (`id`), UNIQUE `id` (`id`))",
)
self.validate_identity(
"CREATE TABLE IF NOT EXISTS industry_info (a BIGINT(20) NOT NULL AUTO_INCREMENT, b BIGINT(20) NOT NULL, c VARCHAR(1000), PRIMARY KEY (a), UNIQUE KEY d (b), KEY e (b))",
"CREATE TABLE IF NOT EXISTS industry_info (a BIGINT(20) NOT NULL AUTO_INCREMENT, b BIGINT(20) NOT NULL, c VARCHAR(1000), PRIMARY KEY (a), UNIQUE d (b), INDEX e (b))",
)
self.validate_identity(
"CREATE TABLE test (ts TIMESTAMP, ts_tz TIMESTAMPTZ, ts_ltz TIMESTAMPLTZ)",
"CREATE TABLE test (ts DATETIME, ts_tz TIMESTAMP, ts_ltz TIMESTAMP)",
)
self.validate_identity(
"ALTER TABLE test_table ALTER COLUMN test_column SET DATA TYPE LONGTEXT",
"ALTER TABLE test_table MODIFY COLUMN test_column LONGTEXT",
)
self.validate_identity(
"CREATE TABLE t (c DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC",
"CREATE TABLE t (c DATETIME DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()) DEFAULT CHARACTER SET=utf8 ROW_FORMAT=DYNAMIC",
)
self.validate_all(
"CREATE TABLE z (a INT) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARACTER SET=utf8 COLLATE=utf8_bin COMMENT='x'",
@ -78,12 +99,6 @@ class TestMySQL(Validator):
"sqlite": "CREATE TABLE z (a INTEGER)",
},
)
self.validate_all(
"CREATE TABLE t (c DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP) DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC",
write={
"mysql": "CREATE TABLE t (c DATETIME DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()) DEFAULT CHARACTER SET=utf8 ROW_FORMAT=DYNAMIC",
},
)
self.validate_all(
"CREATE TABLE x (id int not null auto_increment, primary key (id))",
write={
@ -96,33 +111,9 @@ class TestMySQL(Validator):
"sqlite": "CREATE TABLE x (id INTEGER NOT NULL)",
},
)
self.validate_all(
"CREATE TABLE `foo` (`id` char(36) NOT NULL DEFAULT (uuid()), PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`))",
write={
"mysql": "CREATE TABLE `foo` (`id` CHAR(36) NOT NULL DEFAULT (UUID()), PRIMARY KEY (`id`), UNIQUE `id` (`id`))",
},
)
self.validate_all(
"CREATE TABLE IF NOT EXISTS industry_info (a BIGINT(20) NOT NULL AUTO_INCREMENT, b BIGINT(20) NOT NULL, c VARCHAR(1000), PRIMARY KEY (a), UNIQUE KEY d (b), KEY e (b))",
write={
"mysql": "CREATE TABLE IF NOT EXISTS industry_info (a BIGINT(20) NOT NULL AUTO_INCREMENT, b BIGINT(20) NOT NULL, c VARCHAR(1000), PRIMARY KEY (a), UNIQUE d (b), INDEX e (b))",
},
)
self.validate_all(
"CREATE TABLE test (ts TIMESTAMP, ts_tz TIMESTAMPTZ, ts_ltz TIMESTAMPLTZ)",
write={
"mysql": "CREATE TABLE test (ts DATETIME, ts_tz TIMESTAMP, ts_ltz TIMESTAMP)",
},
)
self.validate_all(
"ALTER TABLE test_table ALTER COLUMN test_column SET DATA TYPE LONGTEXT",
write={
"mysql": "ALTER TABLE test_table MODIFY COLUMN test_column LONGTEXT",
},
)
self.validate_identity("ALTER TABLE test_table ALTER COLUMN test_column SET DEFAULT 1")
def test_identity(self):
self.validate_identity("ALTER TABLE test_table ALTER COLUMN test_column SET DEFAULT 1")
self.validate_identity("SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:00.0000')")
self.validate_identity("SELECT @var1 := 1, @var2")
self.validate_identity("UNLOCK TABLES")

View file

@ -1,4 +1,4 @@
from sqlglot import exp, parse_one
from sqlglot import exp
from sqlglot.errors import UnsupportedError
from tests.dialects.test_dialect import Validator
@ -7,11 +7,18 @@ class TestOracle(Validator):
dialect = "oracle"
def test_oracle(self):
self.validate_identity("REGEXP_REPLACE('source', 'search')")
parse_one("ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol", dialect="oracle").assert_is(
exp.AlterTable
self.validate_all(
"SELECT CONNECT_BY_ROOT x y",
write={
"": "SELECT CONNECT_BY_ROOT(x) AS y",
"oracle": "SELECT CONNECT_BY_ROOT x AS y",
},
)
self.parse_one("ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol").assert_is(exp.AlterTable)
self.validate_identity("CREATE GLOBAL TEMPORARY TABLE t AS SELECT * FROM orders")
self.validate_identity("CREATE PRIVATE TEMPORARY TABLE t AS SELECT * FROM orders")
self.validate_identity("REGEXP_REPLACE('source', 'search')")
self.validate_identity("TIMESTAMP(3) WITH TIME ZONE")
self.validate_identity("CURRENT_TIMESTAMP(precision)")
self.validate_identity("ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol")
@ -88,6 +95,13 @@ class TestOracle(Validator):
)
self.validate_identity("SELECT TO_CHAR(-100, 'L99', 'NL_CURRENCY = '' AusDollars '' ')")
self.validate_all(
"TO_CHAR(x)",
write={
"doris": "CAST(x AS STRING)",
"oracle": "TO_CHAR(x)",
},
)
self.validate_all(
"SELECT TO_CHAR(TIMESTAMP '1999-12-01 10:00:00')",
write={

Some files were not shown because too many files have changed in this diff Show more