1
0
Fork 0

Adding 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:15 +01:00
parent b01402dc30
commit f1aa09959c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
148 changed files with 68457 additions and 63176 deletions

View file

@ -1,6 +1,164 @@
Changelog 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 ## [v21.1.1] - 2024-02-14
### :sparkles: New Features ### :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))* - [`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))*
@ -2633,4 +2791,12 @@ Changelog
[v21.0.1]: https://github.com/tobymao/sqlglot/compare/v21.0.0...v21.0.1 [v21.0.1]: https://github.com/tobymao/sqlglot/compare/v21.0.0...v21.0.1
[v21.0.2]: https://github.com/tobymao/sqlglot/compare/v21.0.1...v21.0.2 [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.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.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 ```sql
'SELECT FROM_UNIXTIME(1618088028295 / 1000)' 'SELECT FROM_UNIXTIME(1618088028295 / POW(10, 3))'
``` ```
SQLGlot can even translate custom time formats: 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 ```python
import sqlglot 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. sqlglot.errors.ParseError: Expecting ). Line 1, Col: 34.
select foo( FROM bar SELECT foo FROM (SELECT baz FROM t
~~~~ ~
``` ```
Structured syntax errors are accessible for programmatic use: Structured syntax errors are accessible for programmatic use:
@ -216,7 +216,7 @@ Structured syntax errors are accessible for programmatic use:
```python ```python
import sqlglot import sqlglot
try: try:
sqlglot.transpile("SELECT foo( FROM bar") sqlglot.transpile("SELECT foo FROM (SELECT baz FROM t")
except sqlglot.errors.ParseError as e: except sqlglot.errors.ParseError as e:
print(e.errors) print(e.errors)
``` ```
@ -225,11 +225,11 @@ except sqlglot.errors.ParseError as e:
[{ [{
'description': 'Expecting )', 'description': 'Expecting )',
'line': 1, 'line': 1,
'col': 16, 'col': 34,
'start_context': 'SELECT foo( ', 'start_context': 'SELECT foo FROM (SELECT baz FROM ',
'highlight': 'FROM', 'highlight': 't',
'end_context': ' bar', 'end_context': '',
'into_expression': None, '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> <p>I tried to parse SQL that should be valid but it failed, why did that happen?</p>
<ul> <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> </ul>
<p>I tried to output SQL but it's not in the correct dialect!</p> <p>I tried to output SQL but it's not in the correct dialect!</p>
<ul> <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> </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> <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> </ul>
<h2 id="examples">Examples</h2> <h2 id="examples">Examples</h2>
@ -206,7 +206,7 @@
</div> </div>
<div class="pdoc-code codehilite"> <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> </code></pre>
</div> </div>
@ -319,13 +319,13 @@
<div class="pdoc-code codehilite"> <div class="pdoc-code codehilite">
<pre><span></span><code><span class="kn">import</span> <span class="nn">sqlglot</span> <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> </code></pre>
</div> </div>
<pre><code><a href="sqlglot/errors.html#ParseError">sqlglot.errors.ParseError</a>: Expecting ). Line 1, Col: 13. <pre><code><a href="sqlglot/errors.html#ParseError">sqlglot.errors.ParseError</a>: Expecting ). Line 1, Col: 34.
select foo( FROM bar SELECT foo FROM (SELECT baz FROM t
~~~~ ~
</code></pre> </code></pre>
<p>Structured syntax errors are accessible for programmatic use:</p> <p>Structured syntax errors are accessible for programmatic use:</p>
@ -333,7 +333,7 @@
<div class="pdoc-code codehilite"> <div class="pdoc-code codehilite">
<pre><span></span><code><span class="kn">import</span> <span class="nn">sqlglot</span> <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="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="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> <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> </code></pre>
@ -343,11 +343,11 @@
<pre><span></span><code><span class="p">[{</span> <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;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;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;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( &#39;</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;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; bar&#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> <span class="s1">&#39;into_expression&#39;</span><span class="p">:</span> <span class="kc">None</span>
<span class="p">}]</span> <span class="p">}]</span>
</code></pre> </code></pre>
</div> </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-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-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-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-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 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-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-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="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 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-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="o">...</span> </span><span id="L-97"><a href="#L-97"><span class="linenos"> 97</span></a>
</span><span id="L-98"><a href="#L-98"><span class="linenos"> 98</span></a> </span><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><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="k">def</span> <span class="nf">parse_one</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">sql</span><span class="p">:</span> <span class="nb">str</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">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-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="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-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="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-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="o">**</span><span class="n">opts</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="p">)</span> <span class="o">-&gt;</span> <span class="n">Expression</span><span class="p">:</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 class="w"> </span><span class="sd">&quot;&quot;&quot;</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"> Parses the given SQL string and returns a syntax tree for the first parsed SQL statement.</span> </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><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"> Args:</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"> sql: the SQL code string to parse.</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"> 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-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"> dialect: the SQL dialect (alias for read)</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 class="sd"> into: the SQLGlot Expression to parse into.</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"> **opts: other `sqlglot.parser.Parser` options.</span> </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><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"> Returns:</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 class="sd"> The syntax tree for the first parsed statement.</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="sd"> &quot;&quot;&quot;</span> </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-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-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><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">if</span> <span class="n">into</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_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-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 class="k">else</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="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-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><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">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-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">if</span> <span class="ow">not</span> <span class="n">expression</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">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-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">return</span> <span class="n">expression</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 class="k">else</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 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-133"><a href="#L-133"><span class="linenos">133</span></a>
</span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a> </span><span id="L-134"><a href="#L-134"><span class="linenos">134</span></a><span class="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><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="k">def</span> <span class="nf">transpile</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">sql</span><span class="p">:</span> <span class="nb">str</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">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-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">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-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="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-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="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-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="o">**</span><span class="n">opts</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="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-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="w"> </span><span class="sd">&quot;&quot;&quot;</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 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-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"> to conform to the target dialect. Each string in the returned list represents a single transformed SQL statement.</span> </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><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"> Args:</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"> sql: the SQL code string to transpile.</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"> 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-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"> 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-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"> 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-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"> the source and the target dialect.</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 class="sd"> error_level: the desired error level of the parser.</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"> **opts: other `sqlglot.generator.Generator` options.</span> </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><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"> Returns:</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="sd"> The list of transpiled SQL statements.</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="sd"> &quot;&quot;&quot;</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="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-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">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-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">return</span> <span class="p">[</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="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-163"><a href="#L-163"><span class="linenos">163</span></a> <span class="p">]</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></pre></div> </span></pre></div>
@ -977,40 +975,40 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#parse_one"></a> <a class="headerlink" href="#parse_one"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="parse_one-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> <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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-110"><a href="#parse_one-110"><span class="linenos">110</span></a> </span><span id="parse_one-108"><a href="#parse_one-108"><span class="linenos">108</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-109"><a href="#parse_one-109"><span class="linenos">109</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-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-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-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-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-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-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-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-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-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-117"><a href="#parse_one-117"><span class="linenos">117</span></a> </span><span id="parse_one-115"><a href="#parse_one-115"><span class="linenos">115</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-116"><a href="#parse_one-116"><span class="linenos">116</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-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-120"><a href="#parse_one-120"><span class="linenos">120</span></a><span class="sd"> &quot;&quot;&quot;</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-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-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><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">if</span> <span class="n">into</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_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-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 class="k">else</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="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-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><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">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-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">if</span> <span class="ow">not</span> <span class="n">expression</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">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-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">return</span> <span class="n">expression</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><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></pre></div> </span></pre></div>
@ -1046,36 +1044,36 @@ make check # Full test suite &amp; linter checks
</div> </div>
<a class="headerlink" href="#transpile"></a> <a class="headerlink" href="#transpile"></a>
<div class="pdoc-code codehilite"><pre><span></span><span id="transpile-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> <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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-148"><a href="#transpile-148"><span class="linenos">148</span></a> </span><span id="transpile-146"><a href="#transpile-146"><span class="linenos">146</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-147"><a href="#transpile-147"><span class="linenos">147</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-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-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-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-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-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-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-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-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-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-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-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-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-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-157"><a href="#transpile-157"><span class="linenos">157</span></a> </span><span id="transpile-155"><a href="#transpile-155"><span class="linenos">155</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-156"><a href="#transpile-156"><span class="linenos">156</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-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-160"><a href="#transpile-160"><span class="linenos">160</span></a><span class="sd"> &quot;&quot;&quot;</span> </span><span id="transpile-158"><a href="#transpile-158"><span class="linenos">158</span></a><span class="sd"> &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-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-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-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-163"><a href="#transpile-163"><span class="linenos">163</span></a> <span class="k">return</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-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-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-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-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-166"><a href="#transpile-166"><span class="linenos">166</span></a> <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> </span></pre></div>

View file

@ -76,8 +76,8 @@
</span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="n">__version_tuple__</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span> </span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="n">__version_tuple__</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="n">version_tuple</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span> </span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="n">version_tuple</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a> </span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a>
</span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;21.1.1&#39;</span> </span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;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">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-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> </span></pre></div>
@ -97,7 +97,7 @@
<section id="version"> <section id="version">
<div class="attr variable"> <div class="attr variable">
<span class="name">version</span><span class="annotation">: str</span> = <span class="name">version</span><span class="annotation">: str</span> =
<span class="default_value">&#39;21.1.1&#39;</span> <span class="default_value">&#39;22.1.1&#39;</span>
</div> </div>
@ -109,7 +109,7 @@
<section id="version_tuple"> <section id="version_tuple">
<div class="attr variable"> <div class="attr variable">
<span class="name">version_tuple</span><span class="annotation">: object</span> = <span class="name">version_tuple</span><span class="annotation">: object</span> =
<span class="default_value">(21, 1, 1)</span> <span class="default_value">(22, 1, 1)</span>
</div> </div>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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-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-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-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-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-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> </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-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-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-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-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-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> </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> <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-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-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-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><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> </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.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.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.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.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.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> <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"> <div class="attr variable">
<span class="name">UNMERGABLE_ARGS</span> = <span class="name">UNMERGABLE_ARGS</span> =
<input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="UNMERGABLE_ARGS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="UNMERGABLE_ARGS-view-value"></label><span class="default_value">{&#39;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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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> <ul>
<li><strong>expression:</strong> The expression to check if it's normalized.</li> <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> Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
</ul> </ul>
</div> </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-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-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-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-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-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> </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> <ul>
<li><strong>expression:</strong> The expression to compute the normalization distance for.</li> <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> Default: False, i.e. we check if it's in Conjunctive Normal Form (CNF).</li>
</ul> </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-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-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-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-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 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-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-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="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 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-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 class="o">...</span> </span><span id="L-19"><a href="#L-19"><span class="linenos">19</span></a>
</span><span id="L-20"><a href="#L-20"><span class="linenos">20</span></a> </span><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><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="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-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="w"> </span><span class="sd">&quot;&quot;&quot;</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 class="sd"> Normalize all unquoted identifiers to either lower or upper case, depending</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"> on the dialect. This essentially makes those identifiers case-insensitive.</span> </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><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 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-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"> identifier of interest:</span> </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-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-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-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><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"> Note:</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 class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</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"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span> </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><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"> Example:</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; import sqlglot</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"> &gt;&gt;&gt; expression = sqlglot.parse_one(&#39;SELECT Bar.A AS A FROM &quot;Foo&quot;.Bar&#39;)</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(expression).sql()</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;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</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 class="sd"> &gt;&gt;&gt; normalize_identifiers(&quot;foo&quot;, dialect=&quot;snowflake&quot;).sql(dialect=&quot;snowflake&quot;)</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"> &#39;FOO&#39;</span> </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><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"> Args:</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 class="sd"> expression: The expression to transform.</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"> dialect: The dialect to use in order to decide how to normalize identifiers.</span> </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><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"> Returns:</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="sd"> The transformed expression.</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 class="sd"> &quot;&quot;&quot;</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="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-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><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 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-55"><a href="#L-55"><span class="linenos">55</span></a>
</span><span id="L-56"><a href="#L-56"><span class="linenos">56</span></a> <span class="n">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-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><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="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-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="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-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="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-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 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-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">node</span> </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><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></pre></div> </span></pre></div>
@ -135,49 +133,49 @@
</div> </div>
<a class="headerlink" href="#normalize_identifiers"></a> <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> <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-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-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-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-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-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-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-27"><a href="#normalize_identifiers-27"><span class="linenos">27</span></a> </span><span id="normalize_identifiers-25"><a href="#normalize_identifiers-25"><span class="linenos">25</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-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-29"><a href="#normalize_identifiers-29"><span class="linenos">29</span></a><span class="sd"> identifier of interest:</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-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-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-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><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"> Note:</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 class="sd"> Some dialects (e.g. BigQuery) treat identifiers as case-insensitive even</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"> when they&#39;re quoted, so in these cases all identifiers are normalized.</span> </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><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"> Example:</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; import sqlglot</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"> &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-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(expression).sql()</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;SELECT bar.a AS a FROM &quot;Foo&quot;.bar&#39;</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 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-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"> &#39;FOO&#39;</span> </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><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"> Args:</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 class="sd"> expression: The expression to transform.</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"> dialect: The dialect to use in order to decide how to normalize identifiers.</span> </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><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"> Returns:</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="sd"> The transformed expression.</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 class="sd"> &quot;&quot;&quot;</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="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-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><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 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-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="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-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><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="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-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="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-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="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-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 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-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">node</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">_normalize</span><span class="p">(</span><span class="n">expression</span><span class="p">)</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></pre></div> </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-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-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-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-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 or not to expand star queries. This is a necessary step</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-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-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-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 or not to isolate table selects.</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 or not to qualify columns.</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 or not to validate 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 or not to run the quote_identifiers step.</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-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-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> </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-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-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-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-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 or not to expand star queries. This is a necessary step</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-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-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-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 or not to isolate table selects.</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 or not to qualify columns.</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 or not to validate 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 or not to run the quote_identifiers step.</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-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-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> </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>db:</strong> Default database name for tables.</li>
<li><strong>catalog:</strong> Default catalog 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>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_alias_refs:</strong> Whether 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_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 for most of the optimizer's rules to work; do not set to False unless you
know what you're doing!</li> know what you're doing!</li>
<li><strong>infer_schema:</strong> Whether or not to infer the schema if missing.</li> <li><strong>infer_schema:</strong> Whether to infer the schema if missing.</li>
<li><strong>isolate_tables:</strong> Whether or not to isolate table selects.</li> <li><strong>isolate_tables:</strong> Whether to isolate table selects.</li>
<li><strong>qualify_columns:</strong> Whether or not to qualify columns.</li> <li><strong>qualify_columns:</strong> Whether to qualify columns.</li>
<li><strong>validate_qualify_columns:</strong> Whether or not to validate columns.</li> <li><strong>validate_qualify_columns:</strong> Whether to validate columns.</li>
<li><strong>quote_identifiers:</strong> Whether or not to run the quote_identifiers step. <li><strong>quote_identifiers:</strong> Whether to run the quote_identifiers step.
This step is necessary to ensure correctness for case sensitive queries. 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> 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> <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-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-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-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-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">Unionable</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-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-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> </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-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-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-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-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">Unionable</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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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">Unionable</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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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> <h6 id="returns">Returns:</h6>
<blockquote> <blockquote>
<p>list[exp.Subqueryable]: subqueries</p> <p>list[exp.Select | exp.Union]: subqueries</p>
</blockquote> </blockquote>
</div> </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-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-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-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-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-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> </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-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-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-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-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">Unionable</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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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="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-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><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><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">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-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="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-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> </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-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-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-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-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-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> </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> <ul>
<li><strong>expression (sqlglot.Expression):</strong> expression to simplify</li> <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> </ul>
<h6 id="returns">Returns:</h6> <h6 id="returns">Returns:</h6>
@ -2546,7 +2560,7 @@ prefix are statically known.</p>
<div class="attr variable"> <div class="attr variable">
<span class="name">DATETRUNC_COMPARISONS</span> = <span class="name">DATETRUNC_COMPARISONS</span> =
<input id="DATETRUNC_COMPARISONS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <input id="DATETRUNC_COMPARISONS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="DATETRUNC_COMPARISONS-view-value"></label><span class="default_value">{&lt;class &#39;<a href="../expressions.html#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> </div>
@ -2626,7 +2640,7 @@ prefix are statically known.</p>
<section id="JOINS"> <section id="JOINS">
<div class="attr variable"> <div class="attr variable">
<span class="name">JOINS</span> = <span class="name">JOINS</span> =
<span class="default_value">{(&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;&#39;, &#39;&#39;)}</span> <span class="default_value">{(&#39;&#39;, &#39;INNER&#39;), (&#39;RIGHT&#39;, &#39;OUTER&#39;), (&#39;RIGHT&#39;, &#39;&#39;), (&#39;&#39;, &#39;&#39;)}</span>
</div> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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-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-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><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-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-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-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-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-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> </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-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-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-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-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-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> </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-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-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-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><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> </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-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-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-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-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-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> </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> </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> <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> <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> <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-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><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> </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> </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-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-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-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-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-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> </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-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-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-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-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-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> </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> <ul>
<li><strong>table:</strong> the target table.</li> <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> </ul>
<h6 id="returns">Returns:</h6> <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> </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> <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> <li>
<a class="function" href="#move_partitioned_by_to_schema_columns">move_partitioned_by_to_schema_columns</a> <a class="function" href="#move_partitioned_by_to_schema_columns">move_partitioned_by_to_schema_columns</a>
</li> </li>
<li>
<a class="function" href="#struct_kv_to_alias">struct_kv_to_alias</a>
</li>
<li> <li>
<a class="function" href="#preprocess">preprocess</a> <a class="function" href="#preprocess">preprocess</a>
</li> </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-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-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-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-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-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> </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-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-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-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-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="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-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="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-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="w"> </span><span class="sd">&quot;&quot;&quot;</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="sd"> Creates a new transform by chaining a sequence of transformations and converts the resulting</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="sd"> expression to SQL, using either the &quot;_sql&quot; method corresponding to the resulting expression,</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="sd"> or the appropriate `Generator.TRANSFORMS` function (when applicable -- see below).</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><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="sd"> Args:</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="sd"> transforms: sequence of transform functions. These will be called in order.</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><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="sd"> Returns:</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 class="sd"> Function that can be used as a generator transform.</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="sd"> &quot;&quot;&quot;</span> </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-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-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="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-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><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="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-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="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-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="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-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><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="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-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 class="k">if</span> <span class="n">_sql_handler</span><span class="p">:</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="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-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><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 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-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="k">if</span> <span class="n">transforms_handler</span><span class="p">:</span> </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="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-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="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-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 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-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><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="c1"># Ensures we don&#39;t enter an infinite loop. This can happen when the original expression</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 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-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="c1"># because then it&#39;d re-enter _to_sql.</span> </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">raise</span> <span class="ne">ValueError</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="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-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 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><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">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-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><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 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-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><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">return</span> <span class="n">_to_sql</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> </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-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-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-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-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-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> </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> </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>
<section id="preprocess"> <section id="preprocess">
<input id="preprocess-view-source" class="view-source-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1"> <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> </div>
<a class="headerlink" href="#preprocess"></a> <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> <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-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-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-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-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-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-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-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-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-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-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-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-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-571"><a href="#preprocess-571"><span class="linenos">571</span></a> </span><span id="preprocess-587"><a href="#preprocess-587"><span class="linenos">587</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-588"><a href="#preprocess-588"><span class="linenos">588</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-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-574"><a href="#preprocess-574"><span class="linenos">574</span></a> </span><span id="preprocess-590"><a href="#preprocess-590"><span class="linenos">590</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-591"><a href="#preprocess-591"><span class="linenos">591</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-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-577"><a href="#preprocess-577"><span class="linenos">577</span></a><span class="sd"> &quot;&quot;&quot;</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-578"><a href="#preprocess-578"><span class="linenos">578</span></a> </span><span id="preprocess-594"><a href="#preprocess-594"><span class="linenos">594</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-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-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-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-581"><a href="#preprocess-581"><span class="linenos">581</span></a> </span><span id="preprocess-597"><a href="#preprocess-597"><span class="linenos">597</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-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-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-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-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-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-585"><a href="#preprocess-585"><span class="linenos">585</span></a> </span><span id="preprocess-601"><a href="#preprocess-601"><span class="linenos">601</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-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-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-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-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-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-589"><a href="#preprocess-589"><span class="linenos">589</span></a> </span><span id="preprocess-605"><a href="#preprocess-605"><span class="linenos">605</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-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-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-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-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-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-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-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-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-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-595"><a href="#preprocess-595"><span class="linenos">595</span></a> </span><span id="preprocess-611"><a href="#preprocess-611"><span class="linenos">611</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-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-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-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-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-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-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-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-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-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-601"><a href="#preprocess-601"><span class="linenos">601</span></a> <span class="p">)</span> </span><span id="preprocess-617"><a href="#preprocess-617"><span class="linenos">617</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-618"><a href="#preprocess-618"><span class="linenos">618</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-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-604"><a href="#preprocess-604"><span class="linenos">604</span></a> </span><span id="preprocess-620"><a href="#preprocess-620"><span class="linenos">620</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-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-606"><a href="#preprocess-606"><span class="linenos">606</span></a> </span><span id="preprocess-622"><a href="#preprocess-622"><span class="linenos">622</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> </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> </span></pre></div>

View file

@ -88,13 +88,11 @@ def parse(
@t.overload @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 @t.overload
def parse_one(sql: str, **opts) -> Expression: def parse_one(sql: str, **opts) -> Expression: ...
...
def parse_one( def parse_one(

View file

@ -140,12 +140,10 @@ class DataFrame:
return cte, name return cte, name
@t.overload @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 @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): def _ensure_list_of_columns(self, cols):
return Column.ensure_cols(ensure_list(cols)) return Column.ensure_cols(ensure_list(cols))

View file

@ -210,7 +210,7 @@ def sec(col: ColumnOrName) -> Column:
def signum(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: 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: 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( 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") alias = expression.args.get("alias")
for tup in expression.find_all(exp.Tuple): 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))) 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)) structs.append(exp.Struct(expressions=expressions))
return self.unnest_sql(exp.Unnest(expressions=[exp.array(*structs, copy=False)])) 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: for grouped in group.expressions:
if grouped.is_int:
continue
alias = aliases.get(grouped) alias = aliases.get(grouped)
if alias: if alias:
grouped.replace(exp.column(alias)) grouped.replace(exp.column(alias))
@ -226,8 +231,11 @@ class BigQuery(Dialect):
# bigquery udfs are case sensitive # bigquery udfs are case sensitive
NORMALIZE_FUNCTIONS = False NORMALIZE_FUNCTIONS = False
# https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_elements_date_time
TIME_MAPPING = { TIME_MAPPING = {
"%D": "%m/%d/%y", "%D": "%m/%d/%y",
"%E*S": "%S.%f",
"%E6S": "%S.%f",
} }
ESCAPE_SEQUENCES = { ESCAPE_SEQUENCES = {
@ -266,14 +274,20 @@ class BigQuery(Dialect):
while isinstance(parent, exp.Dot): while isinstance(parent, exp.Dot):
parent = parent.parent parent = parent.parent
# In BigQuery, CTEs aren't case-sensitive, but table names are (by default, at least). # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive
# The following check is essentially a heuristic to detect tables based on whether or # by default. The following check uses a heuristic to detect tables based on whether
# not they're qualified. It also avoids normalizing UDFs, because they're case-sensitive. # they are qualified. This should generally be correct, because tables in BigQuery
if ( # must be qualified with at least a dataset, unless @@dataset_id is set.
not isinstance(parent, exp.UserDefinedFunction) case_sensitive = (
and not (isinstance(parent, exp.Table) and parent.db) isinstance(parent, exp.UserDefinedFunction)
and not expression.meta.get("is_table") 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()) expression.set("this", expression.this.lower())
return expression return expression
@ -302,6 +316,7 @@ class BigQuery(Dialect):
"BYTES": TokenType.BINARY, "BYTES": TokenType.BINARY,
"CURRENT_DATETIME": TokenType.CURRENT_DATETIME, "CURRENT_DATETIME": TokenType.CURRENT_DATETIME,
"DECLARE": TokenType.COMMAND, "DECLARE": TokenType.COMMAND,
"ELSEIF": TokenType.COMMAND,
"EXCEPTION": TokenType.COMMAND, "EXCEPTION": TokenType.COMMAND,
"FLOAT64": TokenType.DOUBLE, "FLOAT64": TokenType.DOUBLE,
"FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT, "FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
@ -315,8 +330,8 @@ class BigQuery(Dialect):
class Parser(parser.Parser): class Parser(parser.Parser):
PREFIXED_PIVOT_COLUMNS = True PREFIXED_PIVOT_COLUMNS = True
LOG_DEFAULTS_TO_LN = True LOG_DEFAULTS_TO_LN = True
SUPPORTS_IMPLICIT_UNNEST = True
FUNCTIONS = { FUNCTIONS = {
**parser.Parser.FUNCTIONS, **parser.Parser.FUNCTIONS,
@ -410,6 +425,7 @@ class BigQuery(Dialect):
STATEMENT_PARSERS = { STATEMENT_PARSERS = {
**parser.Parser.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.END: lambda self: self._parse_as_command(self._prev),
TokenType.FOR: lambda self: self._parse_for_in(), TokenType.FOR: lambda self: self._parse_for_in(),
} }
@ -433,8 +449,11 @@ class BigQuery(Dialect):
if isinstance(this, exp.Identifier): if isinstance(this, exp.Identifier):
table_name = this.name table_name = this.name
while self._match(TokenType.DASH, advance=False) and self._next: while self._match(TokenType.DASH, advance=False) and self._next:
self._advance(2) text = ""
table_name += f"-{self._prev.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")) this = exp.Identifier(this=table_name, quoted=this.args.get("quoted"))
elif isinstance(this, exp.Literal): elif isinstance(this, exp.Literal):
@ -448,12 +467,28 @@ class BigQuery(Dialect):
return this return this
def _parse_table_parts( 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: ) -> 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: if isinstance(table.this, exp.Identifier) and "." in table.name:
catalog, db, this, *rest = ( 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) 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])) this = exp.Dot.build(t.cast(t.List[exp.Expression], [this, *rest]))
table = exp.Table(this=this, db=db, catalog=catalog) table = exp.Table(this=this, db=db, catalog=catalog)
table.meta["quoted_table"] = True
return table return table
@t.overload @t.overload
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
...
@t.overload @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): def _parse_json_object(self, agg=False):
json_object = super()._parse_json_object() json_object = super()._parse_json_object()
@ -532,6 +566,7 @@ class BigQuery(Dialect):
IGNORE_NULLS_IN_FUNC = True IGNORE_NULLS_IN_FUNC = True
JSON_PATH_SINGLE_QUOTE_ESCAPE = True JSON_PATH_SINGLE_QUOTE_ESCAPE = True
CAN_IMPLEMENT_ARRAY_ANY = True CAN_IMPLEMENT_ARRAY_ANY = True
NAMED_PLACEHOLDER_TOKEN = "@"
TRANSFORMS = { TRANSFORMS = {
**generator.Generator.TRANSFORMS, **generator.Generator.TRANSFORMS,
@ -762,22 +797,25 @@ class BigQuery(Dialect):
"within", "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: def timetostr_sql(self, expression: exp.TimeToStr) -> str:
this = expression.this if isinstance(expression.this, exp.TsOrDsToDate) else expression this = expression.this if isinstance(expression.this, exp.TsOrDsToDate) else expression
return self.func("FORMAT_DATE", self.format_time(expression), this.this) 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: def eq_sql(self, expression: exp.EQ) -> str:
# Operands of = cannot be NULL in BigQuery # Operands of = cannot be NULL in BigQuery
if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null): 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: def array_sql(self, expression: exp.Array) -> str:
first_arg = seq_get(expression.expressions, 0) 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 f"ARRAY{self.wrap(self.sql(first_arg))}"
return inline_array_sql(self, expression) return inline_array_sql(self, expression)

View file

@ -68,7 +68,6 @@ class ClickHouse(Dialect):
"DATE32": TokenType.DATE32, "DATE32": TokenType.DATE32,
"DATETIME64": TokenType.DATETIME64, "DATETIME64": TokenType.DATETIME64,
"DICTIONARY": TokenType.DICTIONARY, "DICTIONARY": TokenType.DICTIONARY,
"ENUM": TokenType.ENUM,
"ENUM8": TokenType.ENUM8, "ENUM8": TokenType.ENUM8,
"ENUM16": TokenType.ENUM16, "ENUM16": TokenType.ENUM16,
"FINAL": TokenType.FINAL, "FINAL": TokenType.FINAL,
@ -93,6 +92,7 @@ class ClickHouse(Dialect):
"AGGREGATEFUNCTION": TokenType.AGGREGATEFUNCTION, "AGGREGATEFUNCTION": TokenType.AGGREGATEFUNCTION,
"SIMPLEAGGREGATEFUNCTION": TokenType.SIMPLEAGGREGATEFUNCTION, "SIMPLEAGGREGATEFUNCTION": TokenType.SIMPLEAGGREGATEFUNCTION,
"SYSTEM": TokenType.COMMAND, "SYSTEM": TokenType.COMMAND,
"PREWHERE": TokenType.PREWHERE,
} }
SINGLE_TOKENS = { SINGLE_TOKENS = {
@ -129,6 +129,7 @@ class ClickHouse(Dialect):
"MAP": parser.build_var_map, "MAP": parser.build_var_map,
"MATCH": exp.RegexpLike.from_arg_list, "MATCH": exp.RegexpLike.from_arg_list,
"RANDCANONICAL": exp.Rand.from_arg_list, "RANDCANONICAL": exp.Rand.from_arg_list,
"TUPLE": exp.Struct.from_arg_list,
"UNIQ": exp.ApproxDistinct.from_arg_list, "UNIQ": exp.ApproxDistinct.from_arg_list,
"XOR": lambda args: exp.Xor(expressions=args), "XOR": lambda args: exp.Xor(expressions=args),
} }
@ -390,7 +391,7 @@ class ClickHouse(Dialect):
return self.expression( return self.expression(
exp.CTE, exp.CTE,
this=self._parse_field(), this=self._parse_conjunction(),
alias=self._parse_table_alias(), alias=self._parse_table_alias(),
scalar=True, scalar=True,
) )
@ -732,3 +733,7 @@ class ClickHouse(Dialect):
return f"{this_name}{self.sep()}{this_properties}{self.sep()}{this_schema}" return f"{this_name}{self.sep()}{this_properties}{self.sep()}{this_schema}"
return super().createable_sql(expression, locations) 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: def columndef_sql(self, expression: exp.ColumnDef, sep: str = " ") -> str:
constraint = expression.find(exp.GeneratedAsIdentityColumnConstraint) constraint = expression.find(exp.GeneratedAsIdentityColumnConstraint)
kind = expression.args.get("kind") kind = expression.kind
if ( if (
constraint constraint
and isinstance(kind, exp.DataType) 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 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. "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 name = expression.this
expression.set( expression.set(
"quoted", "quoted",

View file

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

View file

@ -156,6 +156,3 @@ class Drill(Dialect):
exp.TsOrDiToDi: lambda self, exp.TsOrDiToDi: lambda self,
e: f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS VARCHAR), '-', ''), 1, 8) AS INT)", 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)) 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: def _build_make_timestamp(args: t.List) -> exp.Expression:
if len(args) == 1: if len(args) == 1:
return exp.UnixToTime(this=seq_get(args, 0), scale=exp.UnixToTime.MICROS) 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: def _struct_sql(self: DuckDB.Generator, expression: exp.Struct) -> str:
args: t.List[str] = [] args: t.List[str] = []
for expr in expression.expressions: for i, expr in enumerate(expression.expressions):
if isinstance(expr, exp.Alias): if isinstance(expr, exp.PropertyEQ):
key = expr.alias key = expr.name
value = expr.this
else:
key = expr.name or expr.this.name
value = expr.expression value = expr.expression
else:
key = f"_{i}"
value = expr
args.append(f"{self.sql(exp.Literal.string(key))}: {self.sql(value)}") 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): class DuckDB(Dialect):
NULL_ORDERING = "nulls_are_last" NULL_ORDERING = "nulls_are_last"
SUPPORTS_USER_DEFINED_TYPES = False SUPPORTS_USER_DEFINED_TYPES = False
@ -189,6 +197,7 @@ class DuckDB(Dialect):
"CHARACTER VARYING": TokenType.TEXT, "CHARACTER VARYING": TokenType.TEXT,
"EXCLUDE": TokenType.EXCEPT, "EXCLUDE": TokenType.EXCEPT,
"LOGICAL": TokenType.BOOLEAN, "LOGICAL": TokenType.BOOLEAN,
"ONLY": TokenType.ONLY,
"PIVOT_WIDER": TokenType.PIVOT, "PIVOT_WIDER": TokenType.PIVOT,
"SIGNED": TokenType.INT, "SIGNED": TokenType.INT,
"STRING": TokenType.VARCHAR, "STRING": TokenType.VARCHAR,
@ -213,6 +222,8 @@ class DuckDB(Dialect):
TokenType.TILDA: exp.RegexpLike, TokenType.TILDA: exp.RegexpLike,
} }
FUNCTIONS_WITH_ALIASED_ARGS = {*parser.Parser.FUNCTIONS_WITH_ALIASED_ARGS, "STRUCT_PACK"}
FUNCTIONS = { FUNCTIONS = {
**parser.Parser.FUNCTIONS, **parser.Parser.FUNCTIONS,
"ARRAY_HAS": exp.ArrayContains.from_arg_list, "ARRAY_HAS": exp.ArrayContains.from_arg_list,
@ -261,12 +272,14 @@ class DuckDB(Dialect):
"STRING_SPLIT_REGEX": exp.RegexpSplit.from_arg_list, "STRING_SPLIT_REGEX": exp.RegexpSplit.from_arg_list,
"STRING_TO_ARRAY": exp.Split.from_arg_list, "STRING_TO_ARRAY": exp.Split.from_arg_list,
"STRPTIME": build_formatted_time(exp.StrToTime, "duckdb"), "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": exp.Split.from_arg_list,
"STR_SPLIT_REGEX": exp.RegexpSplit.from_arg_list, "STR_SPLIT_REGEX": exp.RegexpSplit.from_arg_list,
"TO_TIMESTAMP": exp.UnixToTime.from_arg_list, "TO_TIMESTAMP": exp.UnixToTime.from_arg_list,
"UNNEST": exp.Explode.from_arg_list, "UNNEST": exp.Explode.from_arg_list,
"XOR": binary_from_function(exp.BitwiseXor), "XOR": binary_from_function(exp.BitwiseXor),
"GENERATE_SERIES": _build_generate_series(),
"RANGE": _build_generate_series(end_exclusive=True),
} }
FUNCTION_PARSERS = parser.Parser.FUNCTION_PARSERS.copy() FUNCTION_PARSERS = parser.Parser.FUNCTION_PARSERS.copy()
@ -313,6 +326,8 @@ class DuckDB(Dialect):
return pivot_column_names(aggregations, dialect="duckdb") return pivot_column_names(aggregations, dialect="duckdb")
class Generator(generator.Generator): class Generator(generator.Generator):
PARAMETER_TOKEN = "$"
NAMED_PLACEHOLDER_TOKEN = "$"
JOIN_HINTS = False JOIN_HINTS = False
TABLE_HINTS = False TABLE_HINTS = False
QUERY_HINTS = False QUERY_HINTS = False
@ -535,5 +550,22 @@ class DuckDB(Dialect):
return self.sql(expression, "this") return self.sql(expression, "this")
return super().columndef_sql(expression, sep) return super().columndef_sql(expression, sep)
def placeholder_sql(self, expression: exp.Placeholder) -> str: def join_sql(self, expression: exp.Join) -> str:
return f"${expression.name}" if expression.name else "?" 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)) 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: def _str_to_date_sql(self: Hive.Generator, expression: exp.StrToDate) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
time_format = self.format_time(expression) time_format = self.format_time(expression)
@ -536,7 +545,7 @@ class Hive(Dialect):
exp.UnixToStr: lambda self, e: self.func( exp.UnixToStr: lambda self, e: self.func(
"FROM_UNIXTIME", e.this, time_format("hive")(self, e) "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.UnixToTimeStr: rename_func("FROM_UNIXTIME"),
exp.PartitionedByProperty: lambda self, e: f"PARTITIONED BY {self.sql(e, 'this')}", exp.PartitionedByProperty: lambda self, e: f"PARTITIONED BY {self.sql(e, 'this')}",
exp.SerdeProperties: lambda self, e: self.properties(e, prefix="WITH SERDEPROPERTIES"), 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")) return self.properties(properties, prefix=self.seg("TBLPROPERTIES"))
def datatype_sql(self, expression: exp.DataType) -> str: def datatype_sql(self, expression: exp.DataType) -> str:
if ( if expression.this in self.PARAMETERIZABLE_TEXT_TYPES and (
expression.this in (exp.DataType.Type.VARCHAR, exp.DataType.Type.NVARCHAR) not expression.expressions or expression.expressions[0].name == "MAX"
and not expression.expressions
): ):
expression = exp.DataType.build("text") expression = exp.DataType.build("text")
elif expression.is_type(exp.DataType.Type.TEXT) and expression.expressions: 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: def version_sql(self, expression: exp.Version) -> str:
sql = super().version_sql(expression) sql = super().version_sql(expression)
return sql.replace("FOR ", "", 1) 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 = { KEYWORDS = {
**tokens.Tokenizer.KEYWORDS, **tokens.Tokenizer.KEYWORDS,
"CHARSET": TokenType.CHARACTER_SET, "CHARSET": TokenType.CHARACTER_SET,
"ENUM": TokenType.ENUM,
"FORCE": TokenType.FORCE, "FORCE": TokenType.FORCE,
"IGNORE": TokenType.IGNORE, "IGNORE": TokenType.IGNORE,
"LOCK TABLES": TokenType.COMMAND, "LOCK TABLES": TokenType.COMMAND,
@ -391,6 +390,11 @@ class MySQL(Dialect):
"WARNINGS": _show_parser("WARNINGS"), "WARNINGS": _show_parser("WARNINGS"),
} }
PROPERTY_PARSERS = {
**parser.Parser.PROPERTY_PARSERS,
"LOCK": lambda self: self._parse_property_assignment(exp.LockProperty),
}
SET_PARSERS = { SET_PARSERS = {
**parser.Parser.SET_PARSERS, **parser.Parser.SET_PARSERS,
"PERSIST": lambda self: self._parse_set_item_assignment("PERSIST"), "PERSIST": lambda self: self._parse_set_item_assignment("PERSIST"),
@ -416,16 +420,11 @@ class MySQL(Dialect):
"SPATIAL", "SPATIAL",
} }
PROFILE_TYPES = { PROFILE_TYPES: parser.OPTIONS_TYPE = {
"ALL", **dict.fromkeys(("ALL", "CPU", "IPC", "MEMORY", "SOURCE", "SWAPS"), tuple()),
"BLOCK IO", "BLOCK": ("IO",),
"CONTEXT SWITCHES", "CONTEXT": ("SWITCHES",),
"CPU", "PAGE": ("FAULTS",),
"IPC",
"MEMORY",
"PAGE FAULTS",
"SOURCE",
"SWAPS",
} }
TYPE_TOKENS = { TYPE_TOKENS = {

View file

@ -66,6 +66,26 @@ class Oracle(Dialect):
"FF6": "%f", # only 6 digits are supported in python formats "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): class Parser(parser.Parser):
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER, TokenType.KEEP} WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER, TokenType.KEEP}
@ -93,6 +113,21 @@ class Oracle(Dialect):
"XMLTABLE": lambda self: self._parse_xml_table(), "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 = { QUERY_MODIFIER_PARSERS = {
**parser.Parser.QUERY_MODIFIER_PARSERS, **parser.Parser.QUERY_MODIFIER_PARSERS,
TokenType.ORDER_SIBLINGS_BY: lambda self: ("order", self._parse_order()), TokenType.ORDER_SIBLINGS_BY: lambda self: ("order", self._parse_order()),
@ -190,6 +225,7 @@ class Oracle(Dialect):
TRANSFORMS = { TRANSFORMS = {
**generator.Generator.TRANSFORMS, **generator.Generator.TRANSFORMS,
exp.ConnectByRoot: lambda self, e: f"CONNECT_BY_ROOT {self.sql(e, 'this')}",
exp.DateStrToDate: lambda self, e: self.func( exp.DateStrToDate: lambda self, e: self.func(
"TO_DATE", e.this, exp.Literal.string("YYYY-MM-DD") "TO_DATE", e.this, exp.Literal.string("YYYY-MM-DD")
), ),
@ -207,6 +243,7 @@ class Oracle(Dialect):
exp.Substring: rename_func("SUBSTR"), exp.Substring: rename_func("SUBSTR"),
exp.Table: lambda self, e: self.table_sql(e, sep=" "), exp.Table: lambda self, e: self.table_sql(e, sep=" "),
exp.TableSample: lambda self, e: self.tablesample_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.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.ToChar: lambda self, e: self.function_fallback_sql(e),
exp.Trim: trim_sql, exp.Trim: trim_sql,
@ -242,23 +279,3 @@ class Oracle(Dialect):
if len(expression.args.get("actions", [])) > 1: if len(expression.args.get("actions", [])) > 1:
return f"ADD ({actions})" return f"ADD ({actions})"
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: 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: if not kind:
return expression return expression
@ -279,6 +281,7 @@ class Postgres(Dialect):
"TEMP": TokenType.TEMPORARY, "TEMP": TokenType.TEMPORARY,
"CSTRING": TokenType.PSEUDO_TYPE, "CSTRING": TokenType.PSEUDO_TYPE,
"OID": TokenType.OBJECT_IDENTIFIER, "OID": TokenType.OBJECT_IDENTIFIER,
"ONLY": TokenType.ONLY,
"OPERATOR": TokenType.OPERATOR, "OPERATOR": TokenType.OPERATOR,
"REGCLASS": TokenType.OBJECT_IDENTIFIER, "REGCLASS": TokenType.OBJECT_IDENTIFIER,
"REGCOLLATION": TokenType.OBJECT_IDENTIFIER, "REGCOLLATION": TokenType.OBJECT_IDENTIFIER,
@ -451,6 +454,7 @@ class Postgres(Dialect):
exp.JSONBExtract: lambda self, e: self.binary(e, "#>"), exp.JSONBExtract: lambda self, e: self.binary(e, "#>"),
exp.JSONBExtractScalar: lambda self, e: self.binary(e, "#>>"), exp.JSONBExtractScalar: lambda self, e: self.binary(e, "#>>"),
exp.JSONBContains: 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.JSONPathKey: json_path_key_only_name,
exp.JSONPathRoot: lambda *_: "", exp.JSONPathRoot: lambda *_: "",
exp.JSONPathSubscript: lambda self, e: self.json_path_part(e.this), exp.JSONPathSubscript: lambda self, e: self.json_path_part(e.this),
@ -506,6 +510,26 @@ class Postgres(Dialect):
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 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: def bracket_sql(self, expression: exp.Bracket) -> str:
"""Forms like ARRAY[1, 2, 3][3] aren't allowed; we need to wrap the ARRAY.""" """Forms like ARRAY[1, 2, 3][3] aren't allowed; we need to wrap the ARRAY."""
if isinstance(expression.this, exp.Array): if isinstance(expression.this, exp.Array):

View file

@ -453,11 +453,32 @@ class Presto(Dialect):
return super().bracket_sql(expression) return super().bracket_sql(expression)
def struct_sql(self, expression: exp.Struct) -> str: def struct_sql(self, expression: exp.Struct) -> str:
if any(isinstance(arg, self.KEY_VALUE_DEFINITIONS) for arg in expression.expressions): from sqlglot.optimizer.annotate_types import annotate_types
self.unsupported("Struct with key-value definitions is unsupported.")
return self.function_fallback_sql(expression)
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: def interval_sql(self, expression: exp.Interval) -> str:
unit = self.sql(expression, "unit") unit = self.sql(expression, "unit")

View file

@ -70,6 +70,8 @@ class Redshift(Postgres):
"SYSDATE": lambda self: self.expression(exp.CurrentTimestamp, transaction=True), "SYSDATE": lambda self: self.expression(exp.CurrentTimestamp, transaction=True),
} }
SUPPORTS_IMPLICIT_UNNEST = True
def _parse_table( def _parse_table(
self, self,
schema: bool = False, schema: bool = False,
@ -124,27 +126,6 @@ class Redshift(Postgres):
self._retreat(index) self._retreat(index)
return None 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): class Tokenizer(Postgres.Tokenizer):
BIT_STRINGS = [] BIT_STRINGS = []
HEX_STRINGS = [] HEX_STRINGS = []
@ -225,6 +206,18 @@ class Redshift(Postgres):
RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot", "type"} 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: def with_properties(self, properties: exp.Properties) -> str:
"""Redshift doesn't have `WITH` as part of their with_properties so we remove it""" """Redshift doesn't have `WITH` as part of their with_properties so we remove it"""
return self.properties(properties, prefix=" ", suffix="") return self.properties(properties, prefix=" ", suffix="")

View file

@ -21,7 +21,7 @@ from sqlglot.dialects.dialect import (
var_map_sql, var_map_sql,
) )
from sqlglot.expressions import Literal 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 from sqlglot.tokens import TokenType
if t.TYPE_CHECKING: if t.TYPE_CHECKING:
@ -66,7 +66,7 @@ def _build_object_construct(args: t.List) -> t.Union[exp.StarMap, exp.Struct]:
return exp.Struct( return exp.Struct(
expressions=[ 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"), "TERSE OBJECTS": _show_parser("OBJECTS"),
"TABLES": _show_parser("TABLES"), "TABLES": _show_parser("TABLES"),
"TERSE TABLES": _show_parser("TABLES"), "TERSE TABLES": _show_parser("TABLES"),
"VIEWS": _show_parser("VIEWS"),
"TERSE VIEWS": _show_parser("VIEWS"),
"PRIMARY KEYS": _show_parser("PRIMARY KEYS"), "PRIMARY KEYS": _show_parser("PRIMARY KEYS"),
"TERSE 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"), "COLUMNS": _show_parser("COLUMNS"),
"USERS": _show_parser("USERS"), "USERS": _show_parser("USERS"),
"TERSE USERS": _show_parser("USERS"), "TERSE USERS": _show_parser("USERS"),
@ -424,11 +432,13 @@ class Snowflake(Dialect):
FLATTEN_COLUMNS = ["SEQ", "KEY", "PATH", "INDEX", "VALUE", "THIS"] FLATTEN_COLUMNS = ["SEQ", "KEY", "PATH", "INDEX", "VALUE", "THIS"]
SCHEMA_KINDS = {"OBJECTS", "TABLES", "VIEWS", "SEQUENCES", "UNIQUE KEYS", "IMPORTED KEYS"}
def _parse_colon_get_path( def _parse_colon_get_path(
self: parser.Parser, this: t.Optional[exp.Expression] self: parser.Parser, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]: ) -> t.Optional[exp.Expression]:
while True: 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 # 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 # we rearrange the AST appropriately to avoid casting the 2nd argument of GET_PATH
@ -535,7 +545,7 @@ class Snowflake(Dialect):
return table return table
def _parse_table_parts( 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: ) -> exp.Table:
# https://docs.snowflake.com/en/user-guide/querying-stage # https://docs.snowflake.com/en/user-guide/querying-stage
if self._match(TokenType.STRING, advance=False): if self._match(TokenType.STRING, advance=False):
@ -603,7 +613,7 @@ class Snowflake(Dialect):
if self._curr: if self._curr:
scope = self._parse_table_parts() scope = self._parse_table_parts()
elif self._curr: 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() scope = self._parse_table_parts()
return self.expression( return self.expression(
@ -758,10 +768,6 @@ class Snowflake(Dialect):
"POSITION", e.args.get("substr"), e.this, e.args.get("position") "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.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.Stuff: rename_func("INSERT"),
exp.TimestampDiff: lambda self, e: self.func( exp.TimestampDiff: lambda self, e: self.func(
"TIMESTAMPDIFF", e.unit, e.expression, e.this "TIMESTAMPDIFF", e.unit, e.expression, e.this
@ -937,3 +943,19 @@ class Snowflake(Dialect):
def cluster_sql(self, expression: exp.Cluster) -> str: def cluster_sql(self, expression: exp.Cluster) -> str:
return f"CLUSTER BY ({self.expressions(expression, flat=True)})" 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 CREATE_FUNCTION_RETURN_AS = False
def struct_sql(self, expression: exp.Struct) -> str: def struct_sql(self, expression: exp.Struct) -> str:
args = [] from sqlglot.generator import Generator
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)
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: def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
if is_parse_json(expression.this): if is_parse_json(expression.this):

View file

@ -92,6 +92,7 @@ class SQLite(Dialect):
NVL2_SUPPORTED = False NVL2_SUPPORTED = False
JSON_PATH_BRACKETED_KEY_SUPPORTED = False JSON_PATH_BRACKETED_KEY_SUPPORTED = False
SUPPORTS_CREATE_TABLE_LIKE = False SUPPORTS_CREATE_TABLE_LIKE = False
SUPPORTS_TABLE_ALIAS_COLUMNS = False
SUPPORTED_JSON_PATH_PARTS = { SUPPORTED_JSON_PATH_PARTS = {
exp.JSONPathKey, exp.JSONPathKey,
@ -173,6 +174,21 @@ class SQLite(Dialect):
return super().cast_sql(expression) 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: def datediff_sql(self, expression: exp.DateDiff) -> str:
unit = expression.args.get("unit") unit = expression.args.get("unit")
unit = unit.name.upper() if unit else "DAY" unit = unit.name.upper() if unit else "DAY"

View file

@ -18,7 +18,6 @@ from sqlglot.dialects.dialect import (
timestrtotime_sql, timestrtotime_sql,
trim_sql, trim_sql,
) )
from sqlglot.expressions import DataType
from sqlglot.helper import seq_get from sqlglot.helper import seq_get
from sqlglot.time import format_time from sqlglot.time import format_time
from sqlglot.tokens import TokenType 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} 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( def _build_formatted_time(
exp_class: t.Type[E], full_format_mapping: t.Optional[bool] = None 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 # 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 # 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 # 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 = ( unaliased_column_indexes = (
i i for i, c in enumerate(query.selects) if isinstance(c, exp.Column) and not c.alias
for i, c in enumerate(subqueryable.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 # 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: for select_index in unaliased_column_indexes:
alias = subqueryable_selects[select_index] alias = query_selects[select_index]
column = alias.this column = alias.this
if isinstance(column.this, exp.Identifier): if isinstance(column.this, exp.Identifier):
alias.args["alias"].set("quoted", column.this.quoted) alias.args["alias"].set("quoted", column.this.quoted)
@ -420,7 +455,6 @@ class TSQL(Dialect):
"IMAGE": TokenType.IMAGE, "IMAGE": TokenType.IMAGE,
"MONEY": TokenType.MONEY, "MONEY": TokenType.MONEY,
"NTEXT": TokenType.TEXT, "NTEXT": TokenType.TEXT,
"NVARCHAR(MAX)": TokenType.TEXT,
"PRINT": TokenType.COMMAND, "PRINT": TokenType.COMMAND,
"PROC": TokenType.PROCEDURE, "PROC": TokenType.PROCEDURE,
"REAL": TokenType.FLOAT, "REAL": TokenType.FLOAT,
@ -431,15 +465,24 @@ class TSQL(Dialect):
"TOP": TokenType.TOP, "TOP": TokenType.TOP,
"UNIQUEIDENTIFIER": TokenType.UNIQUEIDENTIFIER, "UNIQUEIDENTIFIER": TokenType.UNIQUEIDENTIFIER,
"UPDATE STATISTICS": TokenType.COMMAND, "UPDATE STATISTICS": TokenType.COMMAND,
"VARCHAR(MAX)": TokenType.TEXT,
"XML": TokenType.XML, "XML": TokenType.XML,
"OUTPUT": TokenType.RETURNING, "OUTPUT": TokenType.RETURNING,
"SYSTEM_USER": TokenType.CURRENT_USER, "SYSTEM_USER": TokenType.CURRENT_USER,
"FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT, "FOR SYSTEM_TIME": TokenType.TIMESTAMP_SNAPSHOT,
"OPTION": TokenType.OPTION,
} }
class Parser(parser.Parser): class Parser(parser.Parser):
SET_REQUIRES_ASSIGNMENT_DELIMITER = False 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 = { FUNCTIONS = {
**parser.Parser.FUNCTIONS, **parser.Parser.FUNCTIONS,
@ -472,19 +515,7 @@ class TSQL(Dialect):
"TIMEFROMPARTS": _build_timefromparts, "TIMEFROMPARTS": _build_timefromparts,
} }
JOIN_HINTS = { JOIN_HINTS = {"LOOP", "HASH", "MERGE", "REMOTE"}
"LOOP",
"HASH",
"MERGE",
"REMOTE",
}
VAR_LENGTH_DATATYPES = {
DataType.Type.NVARCHAR,
DataType.Type.VARCHAR,
DataType.Type.CHAR,
DataType.Type.NCHAR,
}
RETURNS_TABLE_TOKENS = parser.Parser.ID_VAR_TOKENS - { RETURNS_TABLE_TOKENS = parser.Parser.ID_VAR_TOKENS - {
TokenType.TABLE, TokenType.TABLE,
@ -496,11 +527,21 @@ class TSQL(Dialect):
TokenType.END: lambda self: self._parse_command(), 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 def _parse_option() -> t.Optional[exp.Expression]:
STRING_ALIASES = True option = self._parse_var_from_options(OPTIONS)
NO_PAREN_IF_COMMANDS = False 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]: def _parse_projections(self) -> t.List[exp.Expression]:
""" """
@ -576,48 +617,13 @@ class TSQL(Dialect):
def _parse_convert( def _parse_convert(
self, strict: bool, safe: t.Optional[bool] = None self, strict: bool, safe: t.Optional[bool] = None
) -> t.Optional[exp.Expression]: ) -> t.Optional[exp.Expression]:
to = self._parse_types() this = self._parse_types()
self._match(TokenType.COMMA) self._match(TokenType.COMMA)
this = self._parse_conjunction() args = [this, *self._parse_csv(self._parse_conjunction)]
convert = exp.Convert.from_arg_list(args)
if not to or not this: convert.set("safe", safe)
return None convert.set("strict", strict)
return convert
# 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)
def _parse_user_defined_function( def _parse_user_defined_function(
self, kind: t.Optional[TokenType] = None self, kind: t.Optional[TokenType] = None
@ -683,6 +689,26 @@ class TSQL(Dialect):
return self.expression(exp.UniqueColumnConstraint, this=this) 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): class Generator(generator.Generator):
LIMIT_IS_TOP = True LIMIT_IS_TOP = True
QUERY_HINTS = False QUERY_HINTS = False
@ -728,6 +754,9 @@ class TSQL(Dialect):
exp.DataType.Type.VARIANT: "SQL_VARIANT", exp.DataType.Type.VARIANT: "SQL_VARIANT",
} }
TYPE_MAPPING.pop(exp.DataType.Type.NCHAR)
TYPE_MAPPING.pop(exp.DataType.Type.NVARCHAR)
TRANSFORMS = { TRANSFORMS = {
**generator.Generator.TRANSFORMS, **generator.Generator.TRANSFORMS,
exp.AnyValue: any_value_to_max_sql, exp.AnyValue: any_value_to_max_sql,
@ -779,6 +808,20 @@ class TSQL(Dialect):
exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 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: def lateral_op(self, expression: exp.Lateral) -> str:
cross_apply = expression.args.get("cross_apply") cross_apply = expression.args.get("cross_apply")
if cross_apply is True: if cross_apply is True:
@ -876,11 +919,10 @@ class TSQL(Dialect):
if ctas_with: if ctas_with:
ctas_with = ctas_with.pop() ctas_with = ctas_with.pop()
subquery = ctas_expression if isinstance(ctas_expression, exp.UNWRAPPED_QUERIES):
if isinstance(subquery, exp.Subqueryable): ctas_expression = ctas_expression.subquery()
subquery = subquery.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("into", exp.Into(this=table))
select_into.set("with", ctas_with) select_into.set("with", ctas_with)
@ -993,3 +1035,6 @@ class TSQL(Dialect):
this_sql = self.sql(this) this_sql = self.sql(this)
expression_sql = self.sql(expression, "expression") expression_sql = self.sql(expression, "expression")
return self.func(name, this_sql, expression_sql if expression_sql else None) 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) 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.Boolean,
exp.DataType, exp.DataType,
exp.Identifier,
exp.Literal, exp.Literal,
exp.Table,
exp.Column,
exp.Lambda,
) )
IGNORED_LEAF_EXPRESSION_TYPES = (exp.Identifier,)
class ChangeDistiller: class ChangeDistiller:
""" """
@ -152,8 +157,16 @@ class ChangeDistiller:
self._source = source self._source = source
self._target = target self._target = target
self._source_index = {id(n): n for n, *_ in self._source.bfs()} self._source_index = {
self._target_index = {id(n): n for n, *_ in self._target.bfs()} 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_source_nodes = set(self._source_index) - set(pre_matched_nodes)
self._unmatched_target_nodes = set(self._target_index) - set(pre_matched_nodes.values()) self._unmatched_target_nodes = set(self._target_index) - set(pre_matched_nodes.values())
self._bigram_histo_cache: t.Dict[int, t.DefaultDict[str, int]] = {} 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: for kept_source_node_id, kept_target_node_id in matching_set:
source_node = self._source_index[kept_source_node_id] source_node = self._source_index[kept_source_node_id]
target_node = self._target_index[kept_target_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( edit_script.extend(
self._generate_move_edits(source_node, target_node, matching_set) self._generate_move_edits(source_node, target_node, matching_set)
) )
@ -307,17 +323,16 @@ def _get_leaves(expression: exp.Expression) -> t.Iterator[exp.Expression]:
has_child_exprs = False has_child_exprs = False
for _, node in expression.iter_expressions(): for _, node in expression.iter_expressions():
has_child_exprs = True if not isinstance(node, IGNORED_LEAF_EXPRESSION_TYPES):
yield from _get_leaves(node) has_child_exprs = True
yield from _get_leaves(node)
if not has_child_exprs: if not has_child_exprs:
yield expression yield expression
def _is_same_type(source: exp.Expression, target: exp.Expression) -> bool: def _is_same_type(source: exp.Expression, target: exp.Expression) -> bool:
if type(source) is type(target) and ( if type(source) is type(target):
not isinstance(source, exp.Identifier) or type(source.parent) is type(target.parent)
):
if isinstance(source, exp.Join): if isinstance(source, exp.Join):
return source.args.get("side") == target.args.get("side") 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: if expression:
for a in expression.args.values(): for a in expression.args.values():
args.extend(ensure_list(a)) 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( def _lcs(

View file

@ -78,7 +78,7 @@ class Context:
def sort(self, key) -> None: def sort(self, key) -> None:
def sort_key(row: t.Tuple) -> t.Tuple: def sort_key(row: t.Tuple) -> t.Tuple:
self.set_row(row) 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) self.table.rows.sort(key=sort_key)

View file

@ -142,7 +142,6 @@ class PythonExecutor:
context = self.context({alias: table}) context = self.context({alias: table})
yield context yield context
types = [] types = []
for row in reader: for row in reader:
if not types: if not types:
for v in row: for v in row:
@ -150,7 +149,11 @@ class PythonExecutor:
types.append(type(ast.literal_eval(v))) types.append(type(ast.literal_eval(v)))
except (ValueError, SyntaxError): except (ValueError, SyntaxError):
types.append(str) 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 yield context.table.reader
def join(self, step, context): def join(self, step, context):

View file

@ -548,12 +548,10 @@ class Expression(metaclass=_Expression):
return new_node return new_node
@t.overload @t.overload
def replace(self, expression: E) -> E: def replace(self, expression: E) -> E: ...
...
@t.overload @t.overload
def replace(self, expression: None) -> None: def replace(self, expression: None) -> None: ...
...
def replace(self, expression): def replace(self, expression):
""" """
@ -913,14 +911,142 @@ class Predicate(Condition):
class DerivedTable(Expression): class DerivedTable(Expression):
@property @property
def selects(self) -> t.List[Expression]: 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 @property
def named_selects(self) -> t.List[str]: def named_selects(self) -> t.List[str]:
return [select.output_name for select in self.selects] 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( def union(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Union: ) -> Union:
@ -946,7 +1072,7 @@ class Unionable(Expression):
def intersect( def intersect(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable: ) -> Intersect:
""" """
Builds an INTERSECT expression. Builds an INTERSECT expression.
@ -969,7 +1095,7 @@ class Unionable(Expression):
def except_( def except_(
self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts self, expression: ExpOrStr, distinct: bool = True, dialect: DialectType = None, **opts
) -> Unionable: ) -> Except:
""" """
Builds an EXCEPT expression. Builds an EXCEPT expression.
@ -991,7 +1117,7 @@ class Unionable(Expression):
return except_(left=self, right=expression, distinct=distinct, dialect=dialect, **opts) return except_(left=self, right=expression, distinct=distinct, dialect=dialect, **opts)
class UDTF(DerivedTable, Unionable): class UDTF(DerivedTable):
@property @property
def selects(self) -> t.List[Expression]: def selects(self) -> t.List[Expression]:
alias = self.args.get("alias") alias = self.args.get("alias")
@ -1017,23 +1143,23 @@ class Refresh(Expression):
class DDL(Expression): class DDL(Expression):
@property @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") with_ = self.args.get("with")
if not with_: return with_.expressions if with_ else []
return []
return with_.expressions
@property
def named_selects(self) -> t.List[str]:
if isinstance(self.expression, Subqueryable):
return self.expression.named_selects
return []
@property @property
def selects(self) -> t.List[Expression]: def selects(self) -> t.List[Expression]:
if isinstance(self.expression, Subqueryable): """If this statement contains a query (e.g. a CTAS), this returns the query's projections."""
return self.expression.selects return self.expression.selects if isinstance(self.expression, Query) else []
return []
@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): class DML(Expression):
@ -1096,6 +1222,19 @@ class Create(DDL):
return kind and kind.upper() 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://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_clone_statement
# https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_copy # 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]: def constraints(self) -> t.List[ColumnConstraint]:
return self.args.get("constraints") or [] return self.args.get("constraints") or []
@property
def kind(self) -> t.Optional[DataType]:
return self.args.get("kind")
class AlterColumn(Expression): class AlterColumn(Expression):
arg_types = { arg_types = {
@ -1367,7 +1510,7 @@ class CharacterSetColumnConstraint(ColumnConstraintKind):
class CheckColumnConstraint(ColumnConstraintKind): class CheckColumnConstraint(ColumnConstraintKind):
pass arg_types = {"this": True, "enforced": False}
class ClusteredColumnConstraint(ColumnConstraintKind): class ClusteredColumnConstraint(ColumnConstraintKind):
@ -1776,6 +1919,10 @@ class Partition(Expression):
arg_types = {"expressions": True} arg_types = {"expressions": True}
class PartitionRange(Expression):
arg_types = {"this": True, "expression": True}
class Fetch(Expression): class Fetch(Expression):
arg_types = { arg_types = {
"direction": False, "direction": False,
@ -2173,6 +2320,10 @@ class LocationProperty(Property):
arg_types = {"this": True} arg_types = {"this": True}
class LockProperty(Property):
arg_types = {"this": True}
class LockingProperty(Property): class LockingProperty(Property):
arg_types = { arg_types = {
"this": False, "this": False,
@ -2310,7 +2461,7 @@ class StabilityProperty(Property):
class TemporaryProperty(Property): class TemporaryProperty(Property):
arg_types = {} arg_types = {"this": False}
class TransformModelProperty(Property): class TransformModelProperty(Property):
@ -2356,6 +2507,7 @@ class Properties(Expression):
"FORMAT": FileFormatProperty, "FORMAT": FileFormatProperty,
"LANGUAGE": LanguageProperty, "LANGUAGE": LanguageProperty,
"LOCATION": LocationProperty, "LOCATION": LocationProperty,
"LOCK": LockProperty,
"PARTITIONED_BY": PartitionedByProperty, "PARTITIONED_BY": PartitionedByProperty,
"RETURNS": ReturnsProperty, "RETURNS": ReturnsProperty,
"ROW_FORMAT": RowFormatProperty, "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 = { QUERY_MODIFIERS = {
"match": False, "match": False,
"laterals": False, "laterals": False,
"joins": False, "joins": False,
"connect": False, "connect": False,
"pivots": False, "pivots": False,
"prewhere": False,
"where": False, "where": False,
"group": False, "group": False,
"having": False, "having": False,
@ -2556,9 +2619,16 @@ QUERY_MODIFIERS = {
"sample": False, "sample": False,
"settings": False, "settings": False,
"format": 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 # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
class WithTableHint(Expression): class WithTableHint(Expression):
arg_types = {"expressions": True} arg_types = {"expressions": True}
@ -2590,6 +2660,7 @@ class Table(Expression):
"pattern": False, "pattern": False,
"ordinality": False, "ordinality": False,
"when": False, "when": False,
"only": False,
} }
@property @property
@ -2638,7 +2709,7 @@ class Table(Expression):
return col return col
class Union(Subqueryable): class Union(Query):
arg_types = { arg_types = {
"with": False, "with": False,
"this": True, "this": True,
@ -2648,34 +2719,6 @@ class Union(Subqueryable):
**QUERY_MODIFIERS, **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( def select(
self, self,
*expressions: t.Optional[ExpOrStr], *expressions: t.Optional[ExpOrStr],
@ -2684,26 +2727,7 @@ class Union(Subqueryable):
copy: bool = True, copy: bool = True,
**opts, **opts,
) -> Union: ) -> Union:
"""Append to or set the SELECT of the union recursively. this = maybe_copy(self, copy)
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.this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts) this.this.unnest().select(*expressions, append=append, dialect=dialect, copy=False, **opts)
this.expression.unnest().select( this.expression.unnest().select(
*expressions, append=append, dialect=dialect, copy=False, **opts *expressions, append=append, dialect=dialect, copy=False, **opts
@ -2800,7 +2824,7 @@ class Lock(Expression):
arg_types = {"update": True, "expressions": False, "wait": False} arg_types = {"update": True, "expressions": False, "wait": False}
class Select(Subqueryable): class Select(Query):
arg_types = { arg_types = {
"with": False, "with": False,
"kind": False, "kind": False,
@ -3011,25 +3035,6 @@ class Select(Subqueryable):
def limit( def limit(
self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts self, expression: ExpOrStr | int, dialect: DialectType = None, copy: bool = True, **opts
) -> Select: ) -> 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( return _apply_builder(
expression=expression, expression=expression,
instance=self, instance=self,
@ -3084,31 +3089,13 @@ class Select(Subqueryable):
copy: bool = True, copy: bool = True,
**opts, **opts,
) -> Select: ) -> 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( return _apply_list_builder(
*expressions, *expressions,
instance=self, instance=self,
arg="expressions", arg="expressions",
append=append, append=append,
dialect=dialect, dialect=dialect,
into=Expression,
copy=copy, copy=copy,
**opts, **opts,
) )
@ -3416,12 +3403,8 @@ class Select(Subqueryable):
The new Create expression. The new Create expression.
""" """
instance = maybe_copy(self, copy) instance = maybe_copy(self, copy)
table_expression = maybe_parse( table_expression = maybe_parse(table, into=Table, dialect=dialect, **opts)
table,
into=Table,
dialect=dialect,
**opts,
)
properties_expression = None properties_expression = None
if properties: if properties:
properties_expression = Properties.from_dict(properties) properties_expression = Properties.from_dict(properties)
@ -3493,7 +3476,10 @@ class Select(Subqueryable):
return self.expressions return self.expressions
class Subquery(DerivedTable, Unionable): UNWRAPPED_QUERIES = (Select, Union)
class Subquery(DerivedTable, Query):
arg_types = { arg_types = {
"this": True, "this": True,
"alias": False, "alias": False,
@ -3502,9 +3488,7 @@ class Subquery(DerivedTable, Unionable):
} }
def unnest(self): def unnest(self):
""" """Returns the first non subquery."""
Returns the first non subquery.
"""
expression = self expression = self
while isinstance(expression, Subquery): while isinstance(expression, Subquery):
expression = expression.this expression = expression.this
@ -3516,6 +3500,18 @@ class Subquery(DerivedTable, Unionable):
expression = t.cast(Subquery, expression.parent) expression = t.cast(Subquery, expression.parent)
return expression 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 @property
def is_wrapper(self) -> bool: def is_wrapper(self) -> bool:
""" """
@ -3603,6 +3599,10 @@ class WindowSpec(Expression):
} }
class PreWhere(Expression):
pass
class Where(Expression): class Where(Expression):
pass pass
@ -3646,6 +3646,10 @@ class Boolean(Condition):
class DataTypeParam(Expression): class DataTypeParam(Expression):
arg_types = {"this": True, "expression": False} arg_types = {"this": True, "expression": False}
@property
def name(self) -> str:
return self.this.name
class DataType(Expression): class DataType(Expression):
arg_types = { arg_types = {
@ -3926,11 +3930,17 @@ class Rollback(Expression):
class AlterTable(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): class AddConstraint(Expression):
arg_types = {"this": False, "expression": False, "enforced": False} arg_types = {"expressions": True}
class DropPartition(Expression): class DropPartition(Expression):
@ -3995,6 +4005,10 @@ class Overlaps(Binary):
class Dot(Binary): class Dot(Binary):
@property
def is_star(self) -> bool:
return self.expression.is_star
@property @property
def name(self) -> str: def name(self) -> str:
return self.expression.name return self.expression.name
@ -4390,6 +4404,10 @@ class Anonymous(Func):
arg_types = {"this": True, "expressions": False} arg_types = {"this": True, "expressions": False}
is_var_len_args = True 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): class AnonymousAggFunc(AggFunc):
arg_types = {"this": True, "expressions": False} arg_types = {"this": True, "expressions": False}
@ -4433,8 +4451,13 @@ class ToChar(Func):
arg_types = {"this": True, "format": False, "nlsparam": False} 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): 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): class ArrayAgg(AggFunc):
@ -4624,6 +4647,11 @@ class ConcatWs(Concat):
_sql_names = ["CONCAT_WS"] _sql_names = ["CONCAT_WS"]
# https://docs.oracle.com/cd/B13789_01/server.101/b10759/operators004.htm#i1035022
class ConnectByRoot(Func):
pass
class Count(AggFunc): class Count(AggFunc):
arg_types = {"this": False, "expressions": False} arg_types = {"this": False, "expressions": False}
is_var_len_args = True is_var_len_args = True
@ -5197,6 +5225,10 @@ class Month(Func):
pass pass
class AddMonths(Func):
arg_types = {"this": True, "expression": True}
class Nvl2(Func): class Nvl2(Func):
arg_types = {"this": True, "true": True, "false": False} arg_types = {"this": True, "true": True, "false": False}
@ -5313,6 +5345,10 @@ class SHA2(Func):
arg_types = {"this": True, "length": False} arg_types = {"this": True, "length": False}
class Sign(Func):
_sql_names = ["SIGN", "SIGNUM"]
class SortArray(Func): class SortArray(Func):
arg_types = {"this": True, "asc": False} arg_types = {"this": True, "asc": False}
@ -5554,7 +5590,13 @@ class Use(Expression):
class Merge(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): class When(Func):
@ -5587,8 +5629,7 @@ def maybe_parse(
prefix: t.Optional[str] = None, prefix: t.Optional[str] = None,
copy: bool = False, copy: bool = False,
**opts, **opts,
) -> E: ) -> E: ...
...
@t.overload @t.overload
@ -5600,8 +5641,7 @@ def maybe_parse(
prefix: t.Optional[str] = None, prefix: t.Optional[str] = None,
copy: bool = False, copy: bool = False,
**opts, **opts,
) -> E: ) -> E: ...
...
def maybe_parse( def maybe_parse(
@ -5653,13 +5693,11 @@ def maybe_parse(
@t.overload @t.overload
def maybe_copy(instance: None, copy: bool = True) -> None: def maybe_copy(instance: None, copy: bool = True) -> None: ...
...
@t.overload @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): 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 @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 @t.overload
def to_identifier( def to_identifier(
name: str | Identifier, quoted: t.Optional[bool] = None, copy: bool = True name: str | Identifier, quoted: t.Optional[bool] = None, copy: bool = True
) -> Identifier: ) -> Identifier: ...
...
def to_identifier(name, quoted=None, copy=True): def to_identifier(name, quoted=None, copy=True):
@ -6362,13 +6398,11 @@ def to_interval(interval: str | Literal) -> Interval:
@t.overload @t.overload
def to_table(sql_path: str | Table, **kwargs) -> Table: def to_table(sql_path: str | Table, **kwargs) -> Table: ...
...
@t.overload @t.overload
def to_table(sql_path: None, **kwargs) -> None: def to_table(sql_path: None, **kwargs) -> None: ...
...
def to_table( def to_table(
@ -6929,7 +6963,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
if isinstance(node, Placeholder): if isinstance(node, Placeholder):
if node.name: if node.name:
new_name = kwargs.get(node.name) new_name = kwargs.get(node.name)
if new_name: if new_name is not None:
return convert(new_name) return convert(new_name)
else: else:
try: try:
@ -6943,7 +6977,7 @@ def replace_placeholders(expression: Expression, *args, **kwargs) -> Expression:
def expand( def expand(
expression: Expression, expression: Expression,
sources: t.Dict[str, Subqueryable], sources: t.Dict[str, Query],
dialect: DialectType = None, dialect: DialectType = None,
copy: bool = True, copy: bool = True,
) -> Expression: ) -> Expression:
@ -6959,7 +6993,7 @@ def expand(
Args: Args:
expression: The expression to expand. 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. dialect: The dialect of the sources dict.
copy: Whether to copy the expression during transformation. Defaults to True. 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]] = { TRANSFORMS: t.Dict[t.Type[exp.Expression], t.Callable[..., str]] = {
**JSON_PATH_PART_TRANSFORMS, **JSON_PATH_PART_TRANSFORMS,
exp.AutoRefreshProperty: lambda self, e: f"AUTO REFRESH {self.sql(e, 'this')}", 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", e: f"{'NOT ' if e.args.get('not_') else ''}CASESPECIFIC",
exp.CharacterSetColumnConstraint: lambda self, e: f"CHARACTER SET {self.sql(e, 'this')}", exp.CharacterSetColumnConstraint: lambda self, e: f"CHARACTER SET {self.sql(e, 'this')}",
exp.CharacterSetProperty: lambda self, exp.CharacterSetProperty: lambda self,
e: f"{'DEFAULT ' if e.args.get('default') else ''}CHARACTER SET={self.sql(e, 'this')}", 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, exp.ClusteredColumnConstraint: lambda self,
e: f"CLUSTERED ({self.expressions(e, 'this', indent=False)})", e: f"CLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}", exp.CollateColumnConstraint: lambda self, e: f"COLLATE {self.sql(e, 'this')}",
exp.CommentColumnConstraint: lambda self, e: f"COMMENT {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( exp.DateAdd: lambda self, e: self.func(
"DATE_ADD", e.this, e.expression, exp.Literal.string(e.text("unit")) "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.DefaultColumnConstraint: lambda self, e: f"DEFAULT {self.sql(e, 'this')}",
exp.EncodeColumnConstraint: lambda self, e: f"ENCODE {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.ExecuteAsProperty: lambda self, e: self.naked_property(e),
exp.ExternalProperty: lambda self, e: "EXTERNAL", exp.ExternalProperty: lambda *_: "EXTERNAL",
exp.HeapProperty: lambda self, e: "HEAP", exp.HeapProperty: lambda *_: "HEAP",
exp.InheritsProperty: lambda self, e: f"INHERITS ({self.expressions(e, flat=True)})", 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.InlineLengthColumnConstraint: lambda self, e: f"INLINE LENGTH {self.sql(e, 'this')}",
exp.InputModelProperty: lambda self, e: f"INPUT{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.LanguageProperty: lambda self, e: self.naked_property(e),
exp.LocationProperty: 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.LogProperty: lambda _, e: f"{'NO ' if e.args.get('no') else ''}LOG",
exp.MaterializedProperty: lambda self, e: "MATERIALIZED", exp.MaterializedProperty: lambda *_: "MATERIALIZED",
exp.NonClusteredColumnConstraint: lambda self, exp.NonClusteredColumnConstraint: lambda self,
e: f"NONCLUSTERED ({self.expressions(e, 'this', indent=False)})", e: f"NONCLUSTERED ({self.expressions(e, 'this', indent=False)})",
exp.NoPrimaryIndexProperty: lambda self, e: "NO PRIMARY INDEX", exp.NoPrimaryIndexProperty: lambda *_: "NO PRIMARY INDEX",
exp.NotForReplicationColumnConstraint: lambda self, e: "NOT FOR REPLICATION", exp.NotForReplicationColumnConstraint: lambda *_: "NOT FOR REPLICATION",
exp.OnCommitProperty: lambda self, exp.OnCommitProperty: lambda _,
e: f"ON COMMIT {'DELETE' if e.args.get('delete') else 'PRESERVE'} ROWS", 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.OnProperty: lambda self, e: f"ON {self.sql(e, 'this')}",
exp.OnUpdateColumnConstraint: lambda self, e: f"ON UPDATE {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.ReturnsProperty: lambda self, e: self.naked_property(e),
exp.SampleProperty: lambda self, e: f"SAMPLE BY {self.sql(e, 'this')}", exp.SampleProperty: lambda self, e: f"SAMPLE BY {self.sql(e, 'this')}",
exp.SetConfigProperty: lambda self, e: 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.SettingsProperty: lambda self, e: f"SETTINGS{self.seg('')}{(self.expressions(e))}",
exp.SqlReadWriteProperty: lambda self, e: e.name, exp.SqlReadWriteProperty: lambda _, e: e.name,
exp.SqlSecurityProperty: lambda self, exp.SqlSecurityProperty: lambda _,
e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}", e: f"SQL SECURITY {'DEFINER' if e.args.get('definer') else 'INVOKER'}",
exp.StabilityProperty: lambda self, e: e.name, exp.StabilityProperty: lambda _, e: e.name,
exp.TemporaryProperty: lambda self, e: "TEMPORARY", exp.TemporaryProperty: lambda *_: "TEMPORARY",
exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}", exp.TitleColumnConstraint: lambda self, e: f"TITLE {self.sql(e, 'this')}",
exp.Timestamp: lambda self, e: self.func("TIMESTAMP", e.this, e.expression), exp.Timestamp: lambda self, e: self.func("TIMESTAMP", e.this, e.expression),
exp.ToTableProperty: lambda self, e: f"TO {self.sql(e.this)}", exp.ToTableProperty: lambda self, e: f"TO {self.sql(e.this)}",
exp.TransformModelProperty: lambda self, e: self.func("TRANSFORM", *e.expressions), exp.TransformModelProperty: lambda self, e: self.func("TRANSFORM", *e.expressions),
exp.TransientProperty: lambda self, e: "TRANSIENT", exp.TransientProperty: lambda *_: "TRANSIENT",
exp.UppercaseColumnConstraint: lambda self, e: "UPPERCASE", exp.UppercaseColumnConstraint: lambda *_: "UPPERCASE",
exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]), exp.VarMap: lambda self, e: self.func("MAP", e.args["keys"], e.args["values"]),
exp.VolatileProperty: lambda self, e: "VOLATILE", exp.VolatileProperty: lambda *_: "VOLATILE",
exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}", exp.WithJournalTableProperty: lambda self, e: f"WITH JOURNAL TABLE={self.sql(e, 'this')}",
} }
@ -356,6 +355,7 @@ class Generator(metaclass=_Generator):
STRUCT_DELIMITER = ("<", ">") STRUCT_DELIMITER = ("<", ">")
PARAMETER_TOKEN = "@" PARAMETER_TOKEN = "@"
NAMED_PLACEHOLDER_TOKEN = ":"
PROPERTIES_LOCATION = { PROPERTIES_LOCATION = {
exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE, exp.AlgorithmProperty: exp.Properties.Location.POST_CREATE,
@ -388,6 +388,7 @@ class Generator(metaclass=_Generator):
exp.LanguageProperty: exp.Properties.Location.POST_SCHEMA, exp.LanguageProperty: exp.Properties.Location.POST_SCHEMA,
exp.LikeProperty: exp.Properties.Location.POST_SCHEMA, exp.LikeProperty: exp.Properties.Location.POST_SCHEMA,
exp.LocationProperty: 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.LockingProperty: exp.Properties.Location.POST_ALIAS,
exp.LogProperty: exp.Properties.Location.POST_NAME, exp.LogProperty: exp.Properties.Location.POST_NAME,
exp.MaterializedProperty: exp.Properties.Location.POST_CREATE, exp.MaterializedProperty: exp.Properties.Location.POST_CREATE,
@ -459,11 +460,16 @@ class Generator(metaclass=_Generator):
exp.Paren, 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 that need to have all CTEs under them bubbled up to them
EXPRESSIONS_WITHOUT_NESTED_CTES: t.Set[t.Type[exp.Expression]] = set() 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__" SENTINEL_LINE_BREAK = "__SQLGLOT__LB__"
__slots__ = ( __slots__ = (
@ -630,7 +636,7 @@ class Generator(metaclass=_Generator):
this_sql = self.indent( this_sql = self.indent(
( (
self.sql(expression) self.sql(expression)
if isinstance(expression, (exp.Select, exp.Union)) if isinstance(expression, exp.UNWRAPPED_QUERIES)
else self.sql(expression, "this") else self.sql(expression, "this")
), ),
level=1, level=1,
@ -1535,8 +1541,8 @@ class Generator(metaclass=_Generator):
expr = self.sql(expression, "expression") expr = self.sql(expression, "expression")
return f"{this} ({kind} => {expr})" return f"{this} ({kind} => {expr})"
def table_sql(self, expression: exp.Table, sep: str = " AS ") -> str: def table_parts(self, expression: exp.Table) -> str:
table = ".".join( return ".".join(
self.sql(part) self.sql(part)
for part in ( for part in (
expression.args.get("catalog"), expression.args.get("catalog"),
@ -1546,6 +1552,9 @@ class Generator(metaclass=_Generator):
if part is not None 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 = self.sql(expression, "version")
version = f" {version}" if version else "" version = f" {version}" if version else ""
alias = self.sql(expression, "alias") alias = self.sql(expression, "alias")
@ -1572,7 +1581,7 @@ class Generator(metaclass=_Generator):
if when: if when:
table = f"{table} {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( def tablesample_sql(
self, self,
@ -1681,7 +1690,7 @@ class Generator(metaclass=_Generator):
alias_node = expression.args.get("alias") alias_node = expression.args.get("alias")
column_names = alias_node and alias_node.columns 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): for i, tup in enumerate(expression.expressions):
row = tup.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 # 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 # 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`. # `sys.setrecursionlimit` to avoid RecursionErrors, or don't set `pretty`.
subqueryable = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects) query = reduce(lambda x, y: exp.union(x, y, distinct=False, copy=False), selects)
return self.subquery_sql( return self.subquery_sql(query.subquery(alias_node and alias_node.this, copy=False))
subqueryable.subquery(alias_node and alias_node.this, copy=False)
)
alias = f" AS {self.sql(alias_node, 'this')}" if alias_node else "" alias = f" AS {self.sql(alias_node, 'this')}" if alias_node else ""
unions = " UNION ALL ".join(self.sql(select) for select in selects) 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 = ", ".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 = self.expressions(expression, flat=True)
expressions = f" BY {expressions}" if expressions else "" expressions = f" BY {expressions}" if expressions else ""
@ -2070,12 +2077,17 @@ class Generator(metaclass=_Generator):
else [] else []
) )
options = self.expressions(expression, key="options")
if options:
options = f" OPTION{self.wrap(options)}"
return csv( return csv(
*sqls, *sqls,
*[self.sql(join) for join in expression.args.get("joins") or []], *[self.sql(join) for join in expression.args.get("joins") or []],
self.sql(expression, "connect"), self.sql(expression, "connect"),
self.sql(expression, "match"), self.sql(expression, "match"),
*[self.sql(lateral) for lateral in expression.args.get("laterals") or []], *[self.sql(lateral) for lateral in expression.args.get("laterals") or []],
self.sql(expression, "prewhere"),
self.sql(expression, "where"), self.sql(expression, "where"),
self.sql(expression, "group"), self.sql(expression, "group"),
self.sql(expression, "having"), self.sql(expression, "having"),
@ -2083,9 +2095,13 @@ class Generator(metaclass=_Generator):
self.sql(expression, "order"), self.sql(expression, "order"),
*offset_limit_modifiers, *offset_limit_modifiers,
*self.after_limit_modifiers(expression), *self.after_limit_modifiers(expression),
options,
sep="", sep="",
) )
def queryoption_sql(self, expression: exp.QueryOption) -> str:
return ""
def offset_limit_modifiers( def offset_limit_modifiers(
self, expression: exp.Expression, fetch: bool, limit: t.Optional[exp.Fetch | exp.Limit] self, expression: exp.Expression, fetch: bool, limit: t.Optional[exp.Fetch | exp.Limit]
) -> t.List[str]: ) -> t.List[str]:
@ -2140,9 +2156,9 @@ class Generator(metaclass=_Generator):
self.sql( self.sql(
exp.Struct( exp.Struct(
expressions=[ expressions=[
exp.column(e.output_name).eq( exp.PropertyEQ(this=e.args.get("alias"), expression=e.this)
e.this if isinstance(e, exp.Alias) else e if isinstance(e, exp.Alias)
) else e
for e in expression.expressions for e in expression.expressions
] ]
) )
@ -2204,7 +2220,7 @@ class Generator(metaclass=_Generator):
return f"@@{kind}{this}" return f"@@{kind}{this}"
def placeholder_sql(self, expression: exp.Placeholder) -> str: 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: def subquery_sql(self, expression: exp.Subquery, sep: str = " AS ") -> str:
alias = self.sql(expression, "alias") alias = self.sql(expression, "alias")
@ -2261,6 +2277,9 @@ class Generator(metaclass=_Generator):
return f"UNNEST({args}){suffix}" return f"UNNEST({args}){suffix}"
def prewhere_sql(self, expression: exp.PreWhere) -> str:
return ""
def where_sql(self, expression: exp.Where) -> str: def where_sql(self, expression: exp.Where) -> str:
this = self.indent(self.sql(expression, "this")) this = self.indent(self.sql(expression, "this"))
return f"{self.seg('WHERE')}{self.sep()}{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: def any_sql(self, expression: exp.Any) -> str:
this = self.sql(expression, "this") this = self.sql(expression, "this")
if isinstance(expression.this, exp.Subqueryable): if isinstance(expression.this, exp.UNWRAPPED_QUERIES):
this = self.wrap(this) this = self.wrap(this)
return f"ANY {this}" return f"ANY {this}"
@ -2568,7 +2587,7 @@ class Generator(metaclass=_Generator):
is_global = " GLOBAL" if expression.args.get("is_global") else "" is_global = " GLOBAL" if expression.args.get("is_global") else ""
if query: if query:
in_sql = self.wrap(query) in_sql = self.wrap(self.sql(query))
elif unnest: elif unnest:
in_sql = self.in_unnest_op(unnest) in_sql = self.in_unnest_op(unnest)
elif field: elif field:
@ -2610,7 +2629,7 @@ class Generator(metaclass=_Generator):
return f"REFERENCES {this}{expressions}{options}" return f"REFERENCES {this}{expressions}{options}"
def anonymous_sql(self, expression: exp.Anonymous) -> str: 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: def paren_sql(self, expression: exp.Paren) -> str:
if isinstance(expression.unnest(), exp.Select): if isinstance(expression.unnest(), exp.Select):
@ -2822,7 +2841,9 @@ class Generator(metaclass=_Generator):
exists = " IF EXISTS" if expression.args.get("exists") else "" exists = " IF EXISTS" if expression.args.get("exists") else ""
only = " ONLY" if expression.args.get("only") 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: def add_column_sql(self, expression: exp.AlterTable) -> str:
if self.ALTER_TABLE_INCLUDE_COLUMN_KEYWORD: if self.ALTER_TABLE_INCLUDE_COLUMN_KEYWORD:
@ -2839,15 +2860,7 @@ class Generator(metaclass=_Generator):
return f"DROP{exists}{expressions}" return f"DROP{exists}{expressions}"
def addconstraint_sql(self, expression: exp.AddConstraint) -> str: def addconstraint_sql(self, expression: exp.AddConstraint) -> str:
this = self.sql(expression, "this") return f"ADD {self.expressions(expression)}"
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_}"
def distinct_sql(self, expression: exp.Distinct) -> str: def distinct_sql(self, expression: exp.Distinct) -> str:
this = self.expressions(expression, flat=True) this = self.expressions(expression, flat=True)
@ -3296,6 +3309,10 @@ class Generator(metaclass=_Generator):
self.unsupported("Unsupported index constraint option.") self.unsupported("Unsupported index constraint option.")
return "" 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: def indexcolumnconstraint_sql(self, expression: exp.IndexColumnConstraint) -> str:
kind = self.sql(expression, "kind") kind = self.sql(expression, "kind")
kind = f"{kind} INDEX" if kind else "INDEX" kind = f"{kind} INDEX" if kind else "INDEX"
@ -3452,9 +3469,87 @@ class Generator(metaclass=_Generator):
return expression return expression
def _ensure_string_if_null(self, values: t.List[exp.Expression]) -> t.List[exp.Expression]: def generateseries_sql(self, expression: exp.GenerateSeries) -> str:
return [ expression.set("is_end_exclusive", None)
exp.func("COALESCE", exp.cast(value, "text"), exp.Literal.string("")) return self.function_fallback_sql(expression)
for value in values
if value 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 @t.overload
def ensure_list(value: t.Collection[T]) -> t.List[T]: def ensure_list(value: t.Collection[T]) -> t.List[T]: ...
...
@t.overload @t.overload
def ensure_list(value: T) -> t.List[T]: def ensure_list(value: T) -> t.List[T]: ...
...
def ensure_list(value): def ensure_list(value):
@ -81,13 +79,11 @@ def ensure_list(value):
@t.overload @t.overload
def ensure_collection(value: t.Collection[T]) -> t.Collection[T]: def ensure_collection(value: t.Collection[T]) -> t.Collection[T]: ...
...
@t.overload @t.overload
def ensure_collection(value: T) -> t.Collection[T]: def ensure_collection(value: T) -> t.Collection[T]: ...
...
def ensure_collection(value): def ensure_collection(value):

View file

@ -1,16 +1,19 @@
from __future__ import annotations from __future__ import annotations
import json import json
import logging
import typing as t import typing as t
from dataclasses import dataclass, field from dataclasses import dataclass, field
from sqlglot import Schema, exp, maybe_parse from sqlglot import Schema, exp, maybe_parse
from sqlglot.errors import SqlglotError 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: if t.TYPE_CHECKING:
from sqlglot.dialects.dialect import DialectType from sqlglot.dialects.dialect import DialectType
logger = logging.getLogger("sqlglot")
@dataclass(frozen=True) @dataclass(frozen=True)
class Node: class Node:
@ -18,7 +21,8 @@ class Node:
expression: exp.Expression expression: exp.Expression
source: exp.Expression source: exp.Expression
downstream: t.List[Node] = field(default_factory=list) downstream: t.List[Node] = field(default_factory=list)
alias: str = "" source_name: str = ""
reference_node_name: str = ""
def walk(self) -> t.Iterator[Node]: def walk(self) -> t.Iterator[Node]:
yield self yield self
@ -67,7 +71,7 @@ def lineage(
column: str | exp.Column, column: str | exp.Column,
sql: str | exp.Expression, sql: str | exp.Expression,
schema: t.Optional[t.Dict | Schema] = None, 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, dialect: DialectType = None,
**kwargs, **kwargs,
) -> Node: ) -> Node:
@ -86,14 +90,12 @@ def lineage(
""" """
expression = maybe_parse(sql, dialect=dialect) expression = maybe_parse(sql, dialect=dialect)
column = normalize_identifiers.normalize_identifiers(column, dialect=dialect).name
if sources: if sources:
expression = exp.expand( expression = exp.expand(
expression, expression,
{ {k: t.cast(exp.Query, maybe_parse(v, dialect=dialect)) for k, v in sources.items()},
k: t.cast(exp.Subqueryable, maybe_parse(v, dialect=dialect))
for k, v in sources.items()
},
dialect=dialect, dialect=dialect,
) )
@ -109,122 +111,141 @@ def lineage(
if not scope: if not scope:
raise SqlglotError("Cannot build lineage, sql must be SELECT") 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):
column: str | int, raise SqlglotError(f"Cannot find column '{column}' in query.")
scope: Scope,
scope_name: t.Optional[str] = None,
upstream: t.Optional[Node] = None,
alias: t.Optional[str] = None,
) -> Node:
aliases = {
dt.alias: dt.comments[0].split()[1]
for dt in scope.derived_tables
if dt.comments and dt.comments[0].startswith("source: ")
}
# Find the specific select clause that is the source of the column we want. return to_node(column, scope, dialect)
# This can either be a specific, named select or a generic `*` clause.
select = (
scope.expression.selects[column] def to_node(
column: str | int,
scope: Scope,
dialect: DialectType,
scope_name: t.Optional[str] = None,
upstream: t.Optional[Node] = None,
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: ")
}
# Find the specific select clause that is the source of the column we want.
# This can either be a specific, named select or a generic `*` clause.
select = (
scope.expression.selects[column]
if isinstance(column, int)
else next(
(select for select in scope.expression.selects if select.alias_or_name == column),
exp.Star() if scope.expression.is_star else scope.expression,
)
)
if isinstance(scope.expression, exp.Union):
upstream = upstream or Node(name="UNION", source=scope.expression, expression=select)
index = (
column
if isinstance(column, int) if isinstance(column, int)
else next( else next(
(select for select in scope.expression.selects if select.alias_or_name == column), (
exp.Star() if scope.expression.is_star else scope.expression, i
for i, select in enumerate(scope.expression.selects)
if select.alias_or_name == column or select.is_star
),
-1, # mypy will not allow a None here, but a negative index should never be returned
) )
) )
if isinstance(scope.expression, exp.Union): if index == -1:
upstream = upstream or Node(name="UNION", source=scope.expression, expression=select) raise ValueError(f"Could not find {column} in {scope.expression}")
index = ( for s in scope.union_scopes:
column to_node(
if isinstance(column, int) index,
else next( scope=s,
( dialect=dialect,
i upstream=upstream,
for i, select in enumerate(scope.expression.selects) source_name=source_name,
if select.alias_or_name == column or select.is_star reference_node_name=reference_node_name,
),
-1, # mypy will not allow a None here, but a negative index should never be returned
)
) )
if index == -1: return upstream
raise ValueError(f"Could not find {column} in {scope.expression}")
for s in scope.union_scopes: if isinstance(scope.expression, exp.Select):
to_node(index, scope=s, upstream=upstream, alias=alias) # For better ergonomics in our node labels, replace the full select with
# a version that has only the column we care about.
# "x", SELECT x, y FROM foo
# => "x", SELECT x FROM foo
source = t.cast(exp.Expression, scope.expression.select(select, append=False))
else:
source = scope.expression
return upstream # Create the node for this step in the lineage chain, and attach it to the previous one.
node = Node(
name=f"{scope_name}.{column}" if scope_name else str(column),
source=source,
expression=select,
source_name=source_name or "",
reference_node_name=reference_node_name or "",
)
if isinstance(scope.expression, exp.Select): if upstream:
# For better ergonomics in our node labels, replace the full select with upstream.downstream.append(node)
# a version that has only the column we care about.
# "x", SELECT x, y FROM foo
# => "x", SELECT x FROM foo
source = t.cast(exp.Expression, scope.expression.select(select, append=False))
else:
source = scope.expression
# Create the node for this step in the lineage chain, and attach it to the previous one. subquery_scopes = {
node = Node( id(subquery_scope.expression): subquery_scope for subquery_scope in scope.subquery_scopes
name=f"{scope_name}.{column}" if scope_name else str(column), }
source=source,
expression=select,
alias=alias or "",
)
if upstream: for subquery in find_all_in_scope(select, exp.UNWRAPPED_QUERIES):
upstream.downstream.append(node) subquery_scope = subquery_scopes.get(id(subquery))
if not subquery_scope:
logger.warning(f"Unknown subquery scope: {subquery.sql(dialect=dialect)}")
continue
subquery_scopes = { for name in subquery.named_selects:
id(subquery_scope.expression): subquery_scope to_node(name, scope=subquery_scope, dialect=dialect, upstream=node)
for subquery_scope in scope.subquery_scopes
}
for subquery in find_all_in_scope(select, exp.Subqueryable):
subquery_scope = subquery_scopes[id(subquery)]
for name in subquery.named_selects:
to_node(name, scope=subquery_scope, upstream=node)
# if the select is a star add all scope sources as downstreams
if select.is_star:
for source in scope.sources.values():
if isinstance(source, Scope):
source = source.expression
node.downstream.append(Node(name=select.sql(), source=source, expression=source))
# Find all columns that went into creating this one to list their lineage nodes.
source_columns = set(find_all_in_scope(select, exp.Column))
# If the source is a UDTF find columns used in the UTDF to generate the table
if isinstance(source, exp.UDTF):
source_columns |= set(source.find_all(exp.Column))
for c in source_columns:
table = c.table
source = scope.sources.get(table)
# if the select is a star add all scope sources as downstreams
if select.is_star:
for source in scope.sources.values():
if isinstance(source, Scope): if isinstance(source, Scope):
# The table itself came from a more specific scope. Recurse into that one using the unaliased column name. source = source.expression
to_node( node.downstream.append(Node(name=select.sql(), source=source, expression=source))
c.name,
scope=source,
scope_name=table,
upstream=node,
alias=aliases.get(table) or alias,
)
else:
# The source is not a scope - we've reached the end of the line. At this point, if a source is not found
# it means this column's lineage is unknown. This can happen if the definition of a source used in a query
# is not passed into the `sources` map.
source = source or exp.Placeholder()
node.downstream.append(Node(name=c.sql(), source=source, expression=source))
return node # Find all columns that went into creating this one to list their lineage nodes.
source_columns = set(find_all_in_scope(select, exp.Column))
return to_node(column if isinstance(column, str) else column.name, scope) # If the source is a UDTF find columns used in the UTDF to generate the table
if isinstance(source, exp.UDTF):
source_columns |= set(source.find_all(exp.Column))
for c in source_columns:
table = c.table
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,
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
# it means this column's lineage is unknown. This can happen if the definition of a source used in a query
# is not passed into the `sources` map.
source = source or exp.Placeholder()
node.downstream.append(Node(name=c.sql(), source=source, expression=source))
return node
class GraphHTML: class GraphHTML:

View file

@ -191,6 +191,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
exp.DateToDi, exp.DateToDi,
exp.Floor, exp.Floor,
exp.Levenshtein, exp.Levenshtein,
exp.Sign,
exp.StrPosition, exp.StrPosition,
exp.TsOrDiToDi, exp.TsOrDiToDi,
}, },
@ -262,6 +263,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
exp.DateTrunc: lambda self, e: self._annotate_timeunit(e), exp.DateTrunc: lambda self, e: self._annotate_timeunit(e),
exp.Distinct: lambda self, e: self._annotate_by_args(e, "expressions"), exp.Distinct: lambda self, e: self._annotate_by_args(e, "expressions"),
exp.Div: lambda self, e: self._annotate_div(e), 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.Explode: lambda self, e: self._annotate_explode(e),
exp.Filter: lambda self, e: self._annotate_by_args(e, "this"), exp.Filter: lambda self, e: self._annotate_by_args(e, "this"),
exp.If: lambda self, e: self._annotate_by_args(e, "true", "false"), 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.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.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.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.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.Sum: lambda self, e: self._annotate_by_args(e, "this", "expressions", promote=True),
exp.Timestamp: lambda self, e: self._annotate_with_type( exp.Timestamp: lambda self, e: self._annotate_with_type(
e, e,
exp.DataType.Type.TIMESTAMPTZ if e.args.get("with_tz") else exp.DataType.Type.TIMESTAMP, 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.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.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 = { NESTED_TYPES = {
@ -380,8 +384,11 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
source = scope.sources.get(col.table) source = scope.sources.get(col.table)
if isinstance(source, exp.Table): if isinstance(source, exp.Table):
self._set_type(col, self.schema.get_column_type(source, col)) 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:
self._set_type(col, selects[col.table][col.name].type) 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 # Then (possibly) annotate the remaining expressions in the scope
self._maybe_annotate(scope.expression) self._maybe_annotate(scope.expression)
@ -514,7 +521,14 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
last_datatype = None last_datatype = None
for expr in expressions: 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) self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
@ -594,7 +608,26 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
return expression 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: def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
self._annotate_args(expression) self._annotate_args(expression)
self._set_type(expression, seq_get(expression.this.type.expressions, 0)) self._set_type(expression, seq_get(expression.this.type.expressions, 0))
return expression 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 @t.overload
def normalize_identifiers(expression: E, dialect: DialectType = None) -> E: def normalize_identifiers(expression: E, dialect: DialectType = None) -> E: ...
...
@t.overload @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): 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 example, `col1` and `col2` will be dropped in SELECT ... FROM (SELECT ...) AS foo(col1, col2)
""" """
for derived_table in derived_tables: 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") table_alias = derived_table.args.get("alias")
if table_alias: if table_alias:
table_alias.args.pop("columns", None) 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 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)) alias_expr, i = alias_to_expression.get(column.name, (None, 1))
double_agg = ( 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 if alias_expr
else False else False
) )
@ -404,7 +412,7 @@ def _expand_stars(
tables = list(scope.selected_sources) tables = list(scope.selected_sources)
_add_except_columns(expression, tables, except_columns) _add_except_columns(expression, tables, except_columns)
_add_replace_columns(expression, tables, replace_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] tables = [expression.table]
_add_except_columns(expression.this, tables, except_columns) _add_except_columns(expression.this, tables, except_columns)
_add_replace_columns(expression.this, tables, replace_columns) _add_replace_columns(expression.this, tables, replace_columns)
@ -437,7 +445,7 @@ def _expand_stars(
if pivot_columns: if pivot_columns:
new_selections.extend( 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 for name in pivot_columns
if name not in columns_to_exclude 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 # 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) scope.expression.set("expressions", new_selections)
@ -528,7 +536,8 @@ def qualify_outputs(scope_or_expression: Scope | exp.Expression) -> None:
new_selections.append(selection) new_selections.append(selection)
scope.expression.set("expressions", new_selections) if isinstance(scope.expression, exp.Select):
scope.expression.set("expressions", new_selections)
def quote_identifiers(expression: E, dialect: DialectType = None, identify: bool = True) -> E: def quote_identifiers(expression: E, dialect: DialectType = None, identify: bool = True) -> E:
@ -615,7 +624,7 @@ class Resolver:
node, _ = self.scope.selected_sources.get(table_name) 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: while node and node.alias != table_name:
node = node.parent node = node.parent

View file

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

View file

@ -138,7 +138,7 @@ class Scope:
and _is_derived_table(node) and _is_derived_table(node)
): ):
self._derived_tables.append(node) self._derived_tables.append(node)
elif isinstance(node, exp.Subqueryable): elif isinstance(node, exp.UNWRAPPED_QUERIES):
self._subqueries.append(node) self._subqueries.append(node)
self._collected = True self._collected = True
@ -225,7 +225,7 @@ class Scope:
SELECT * FROM x WHERE a IN (SELECT ...) <- that's a subquery SELECT * FROM x WHERE a IN (SELECT ...) <- that's a subquery
Returns: Returns:
list[exp.Subqueryable]: subqueries list[exp.Select | exp.Union]: subqueries
""" """
self._ensure_collected() self._ensure_collected()
return self._subqueries return self._subqueries
@ -486,8 +486,8 @@ def traverse_scope(expression: exp.Expression) -> t.List[Scope]:
Returns: Returns:
list[Scope]: scope instances list[Scope]: scope instances
""" """
if isinstance(expression, exp.Unionable) or ( if isinstance(expression, exp.Query) or (
isinstance(expression, exp.DDL) and isinstance(expression.expression, exp.Unionable) isinstance(expression, exp.DDL) and isinstance(expression.expression, exp.Query)
): ):
return list(_traverse_scope(Scope(expression))) 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 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. 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): def _traverse_tables(scope):
@ -786,7 +786,7 @@ def walk_in_scope(expression, bfs=True, prune=None):
and _is_derived_table(node) and _is_derived_table(node)
) )
or isinstance(node, exp.UDTF) or isinstance(node, exp.UDTF)
or isinstance(node, exp.Subqueryable) or isinstance(node, exp.UNWRAPPED_QUERIES)
): ):
crossed_scope_boundary = True crossed_scope_boundary = True

View file

@ -1185,7 +1185,7 @@ def gen(expression: t.Any) -> str:
GEN_MAP = { GEN_MAP = {
exp.Add: lambda e: _binary(e, "+"), exp.Add: lambda e: _binary(e, "+"),
exp.And: lambda e: _binary(e, "AND"), 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.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.Boolean: lambda e: "TRUE" if e.this else "FALSE",
exp.Bracket: lambda e: f"{gen(e.this)}[{gen(e.expressions)}]", 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: def _binary(e: exp.Binary, op: str) -> str:
return f"{gen(e.left)} {op} {gen(e.right)}" return f"{gen(e.left)} {op} {gen(e.right)}"

View file

@ -94,8 +94,20 @@ def unnest(select, parent_select, next_alias_name):
else: else:
_replace(predicate, join_key_not_null) _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( parent_select.join(
select.group_by(value.this, copy=False), select,
on=column.eq(join_key), on=column.eq(join_key),
join_type="LEFT", join_type="LEFT",
join_alias=alias, join_alias=alias,

View file

@ -17,6 +17,8 @@ if t.TYPE_CHECKING:
logger = logging.getLogger("sqlglot") 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: def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
if len(args) == 1 and args[0].is_star: if len(args) == 1 and args[0].is_star:
@ -367,6 +369,7 @@ class Parser(metaclass=_Parser):
TokenType.TEMPORARY, TokenType.TEMPORARY,
TokenType.TOP, TokenType.TOP,
TokenType.TRUE, TokenType.TRUE,
TokenType.TRUNCATE,
TokenType.UNIQUE, TokenType.UNIQUE,
TokenType.UNPIVOT, TokenType.UNPIVOT,
TokenType.UPDATE, TokenType.UPDATE,
@ -435,6 +438,7 @@ class Parser(metaclass=_Parser):
TokenType.TABLE, TokenType.TABLE,
TokenType.TIMESTAMP, TokenType.TIMESTAMP,
TokenType.TIMESTAMPTZ, TokenType.TIMESTAMPTZ,
TokenType.TRUNCATE,
TokenType.WINDOW, TokenType.WINDOW,
TokenType.XOR, TokenType.XOR,
*TYPE_TOKENS, *TYPE_TOKENS,
@ -578,7 +582,7 @@ class Parser(metaclass=_Parser):
exp.Column: lambda self: self._parse_column(), exp.Column: lambda self: self._parse_column(),
exp.Condition: lambda self: self._parse_conjunction(), exp.Condition: lambda self: self._parse_conjunction(),
exp.DataType: lambda self: self._parse_types(allow_identifiers=False), 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.From: lambda self: self._parse_from(),
exp.Group: lambda self: self._parse_group(), exp.Group: lambda self: self._parse_group(),
exp.Having: lambda self: self._parse_having(), exp.Having: lambda self: self._parse_having(),
@ -625,10 +629,10 @@ class Parser(metaclass=_Parser):
TokenType.SET: lambda self: self._parse_set(), TokenType.SET: lambda self: self._parse_set(),
TokenType.UNCACHE: lambda self: self._parse_uncache(), TokenType.UNCACHE: lambda self: self._parse_uncache(),
TokenType.UPDATE: lambda self: self._parse_update(), TokenType.UPDATE: lambda self: self._parse_update(),
TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
TokenType.USE: lambda self: self.expression( TokenType.USE: lambda self: self.expression(
exp.Use, exp.Use,
kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA")) kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
and exp.var(self._prev.text),
this=self._parse_table(schema=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()), TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
} }
PRIMARY_PARSERS = { STRING_PARSERS = {
TokenType.STRING: lambda self, token: self.expression( TokenType.HEREDOC_STRING: lambda self, token: self.expression(
exp.Literal, this=token.text, is_string=True 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( TokenType.NATIONAL_STRING: lambda self, token: self.expression(
exp.National, this=token.text exp.National, this=token.text
), ),
TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text), TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
TokenType.HEREDOC_STRING: lambda self, token: self.expression( TokenType.STRING: lambda self, token: self.expression(
exp.RawString, this=token.text exp.Literal, this=token.text, is_string=True
), ),
TokenType.UNICODE_STRING: lambda self, token: self.expression( TokenType.UNICODE_STRING: lambda self, token: self.expression(
exp.UnicodeString, exp.UnicodeString,
this=token.text, this=token.text,
escape=self._match_text_seq("UESCAPE") and self._parse_string(), 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.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 = { PLACEHOLDER_PARSERS = {
@ -799,7 +811,9 @@ class Parser(metaclass=_Parser):
exp.CharacterSetColumnConstraint, this=self._parse_var_or_string() exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
), ),
"CHECK": lambda self: self.expression( "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( "COLLATE": lambda self: self.expression(
exp.CollateColumnConstraint, this=self._parse_var() exp.CollateColumnConstraint, this=self._parse_var()
@ -873,6 +887,8 @@ class Parser(metaclass=_Parser):
FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"} FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
FUNCTION_PARSERS = { FUNCTION_PARSERS = {
"CAST": lambda self: self._parse_cast(self.STRICT_CAST), "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
"CONVERT": lambda self: self._parse_convert(self.STRICT_CAST), "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
@ -895,6 +911,7 @@ class Parser(metaclass=_Parser):
QUERY_MODIFIER_PARSERS = { QUERY_MODIFIER_PARSERS = {
TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()), 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.WHERE: lambda self: ("where", self._parse_where()),
TokenType.GROUP_BY: lambda self: ("group", self._parse_group()), TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
TokenType.HAVING: lambda self: ("having", self._parse_having()), 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), 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} DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE} PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"} TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
TRANSACTION_CHARACTERISTICS = { TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
"ISOLATION LEVEL REPEATABLE READ", "ISOLATION": (
"ISOLATION LEVEL READ COMMITTED", ("LEVEL", "REPEATABLE", "READ"),
"ISOLATION LEVEL READ UNCOMMITTED", ("LEVEL", "READ", "COMMITTED"),
"ISOLATION LEVEL SERIALIZABLE", ("LEVEL", "READ", "UNCOMITTED"),
"READ WRITE", ("LEVEL", "SERIALIZABLE"),
"READ ONLY", ),
"READ": ("WRITE", "ONLY"),
} }
USABLES: OPTIONS_TYPE = dict.fromkeys(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"), tuple())
INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"} INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
CLONE_KEYWORDS = {"CLONE", "COPY"} 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 # If this is True and '(' is not found, the keyword will be treated as an identifier
VALUES_FOLLOWED_BY_PAREN = True 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__ = ( __slots__ = (
"error_level", "error_level",
"error_message_context", "error_message_context",
@ -2450,10 +2471,37 @@ class Parser(metaclass=_Parser):
alias=self._parse_table_alias() if parse_alias else None, 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( def _parse_query_modifiers(
self, this: t.Optional[exp.Expression] self, this: t.Optional[exp.Expression]
) -> 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): for join in iter(self._parse_join, None):
this.append("joins", join) this.append("joins", join)
for lateral in iter(self._parse_lateral, None): for lateral in iter(self._parse_lateral, None):
@ -2478,6 +2526,10 @@ class Parser(metaclass=_Parser):
offset.set("expressions", limit_by_expressions) offset.set("expressions", limit_by_expressions)
continue continue
break break
if self.SUPPORTS_IMPLICIT_UNNEST and this and "from" in this.args:
this = self._implicit_unnests_to_explicit(this)
return this return this
def _parse_hint(self) -> t.Optional[exp.Hint]: def _parse_hint(self) -> t.Optional[exp.Hint]:
@ -2803,7 +2855,9 @@ class Parser(metaclass=_Parser):
or self._parse_placeholder() 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 catalog = None
db = None db = None
table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema) table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
@ -2817,8 +2871,20 @@ class Parser(metaclass=_Parser):
else: else:
catalog = db catalog = db
db = table db = table
# "" used for tsql FROM a..b case
table = self._parse_table_part(schema=schema) or "" 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: if is_db_reference:
catalog = db catalog = db
db = table db = table
@ -2861,6 +2927,9 @@ class Parser(metaclass=_Parser):
bracket = parse_bracket and self._parse_bracket(None) bracket = parse_bracket and self._parse_bracket(None)
bracket = self.expression(exp.Table, this=bracket) if bracket else None bracket = self.expression(exp.Table, this=bracket) if bracket else None
only = self._match(TokenType.ONLY)
this = t.cast( this = t.cast(
exp.Expression, exp.Expression,
bracket 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: if schema:
return self._parse_schema(this=this) 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]: def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
return [agg.alias for agg in aggregations] 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]: def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
if not skip_where_token and not self._match(TokenType.WHERE): if not skip_where_token and not self._match(TokenType.WHERE):
return None return None
@ -3291,8 +3374,12 @@ class Parser(metaclass=_Parser):
return None return None
return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered)) 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() this = parse_method() if parse_method else self._parse_conjunction()
if not this:
return None
asc = self._match(TokenType.ASC) asc = self._match(TokenType.ASC)
desc = self._match(TokenType.DESC) or (asc and False) desc = self._match(TokenType.DESC) or (asc and False)
@ -3510,7 +3597,7 @@ class Parser(metaclass=_Parser):
if self._match_text_seq("DISTINCT", "FROM"): if self._match_text_seq("DISTINCT", "FROM"):
klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ 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() expression = self._parse_null() or self._parse_boolean()
if not expression: if not expression:
@ -3528,7 +3615,7 @@ class Parser(metaclass=_Parser):
matched_l_paren = self._prev.token_type == TokenType.L_PAREN matched_l_paren = self._prev.token_type == TokenType.L_PAREN
expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias)) 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]) this = self.expression(exp.In, this=this, query=expressions[0])
else: else:
this = self.expression(exp.In, this=this, expressions=expressions) 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)) 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( this = self._parse_set_operations(
self._parse_subquery(this=this, parse_alias=False) self._parse_subquery(this=this, parse_alias=False)
) )
@ -4064,6 +4151,9 @@ class Parser(metaclass=_Parser):
alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
args = self._parse_csv(lambda: self._parse_lambda(alias=alias)) 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 function and not anonymous:
if "dialect" in function.__code__.co_varnames: if "dialect" in function.__code__.co_varnames:
func = function(args, dialect=self.dialect) func = function(args, dialect=self.dialect)
@ -4076,6 +4166,8 @@ class Parser(metaclass=_Parser):
this = func this = func
else: else:
if token_type == TokenType.IDENTIFIER:
this = exp.Identifier(this=this, quoted=True)
this = self.expression(exp.Anonymous, this=this, expressions=args) this = self.expression(exp.Anonymous, this=this, expressions=args)
if isinstance(this, exp.Expression): if isinstance(this, exp.Expression):
@ -4084,6 +4176,26 @@ class Parser(metaclass=_Parser):
self._match_r_paren(this) self._match_r_paren(this)
return self._parse_window(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]: def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
return self._parse_column_def(self._parse_id_var()) 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 # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
if bracket_kind == TokenType.L_BRACE: 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": elif not this or this.name.upper() == "ARRAY":
this = self.expression(exp.Array, expressions=expressions) this = self.expression(exp.Array, expressions=expressions)
else: else:
@ -4747,12 +4859,10 @@ class Parser(metaclass=_Parser):
return None return None
@t.overload @t.overload
def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
...
@t.overload @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): def _parse_json_object(self, agg=False):
star = self._parse_star() star = self._parse_star()
@ -5140,16 +5250,16 @@ class Parser(metaclass=_Parser):
return None return None
def _parse_string(self) -> t.Optional[exp.Expression]: def _parse_string(self) -> t.Optional[exp.Expression]:
if self._match_set((TokenType.STRING, TokenType.RAW_STRING)): if self._match_set(self.STRING_PARSERS):
return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev) return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
return self._parse_placeholder() return self._parse_placeholder()
def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]: def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True) return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
def _parse_number(self) -> t.Optional[exp.Expression]: def _parse_number(self) -> t.Optional[exp.Expression]:
if self._match(TokenType.NUMBER): if self._match_set(self.NUMERIC_PARSERS):
return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev) return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
return self._parse_placeholder() return self._parse_placeholder()
def _parse_identifier(self) -> t.Optional[exp.Expression]: 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]: def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
return self._parse_var() or self._parse_string() 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]: def _parse_null(self) -> t.Optional[exp.Expression]:
if self._match_set(self.NULL_TOKENS): if self._match_set(self.NULL_TOKENS):
return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev) return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
@ -5200,16 +5313,12 @@ class Parser(metaclass=_Parser):
return self._parse_placeholder() return self._parse_placeholder()
def _parse_parameter(self) -> exp.Parameter: 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) self._match(TokenType.L_BRACE)
this = _parse_parameter_part() this = self._parse_identifier() or self._parse_primary_or_var()
expression = self._match(TokenType.COLON) and _parse_parameter_part() expression = self._match(TokenType.COLON) and (
self._parse_identifier() or self._parse_primary_or_var()
)
self._match(TokenType.R_BRACE) self._match(TokenType.R_BRACE)
return self.expression(exp.Parameter, this=this, expression=expression) return self.expression(exp.Parameter, this=this, expression=expression)
def _parse_placeholder(self) -> t.Optional[exp.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 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]: def _parse_alter_table_add(self) -> t.List[exp.Expression]:
index = self._index - 1 index = self._index - 1
if self._match_set(self.ADD_CONSTRAINT_TOKENS): if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
return self._parse_csv(self._parse_add_constraint) return self._parse_csv(
lambda: self.expression(
exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
)
)
self._retreat(index) self._retreat(index)
if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"): 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 parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
if parser: if parser:
actions = ensure_list(parser(self)) actions = ensure_list(parser(self))
options = self._parse_csv(self._parse_property)
if not self._curr and actions: if not self._curr and actions:
return self.expression( return self.expression(
@ -5480,6 +5570,7 @@ class Parser(metaclass=_Parser):
exists=exists, exists=exists,
actions=actions, actions=actions,
only=only, only=only,
options=options,
) )
return self._parse_as_command(start) return self._parse_as_command(start)
@ -5610,11 +5701,34 @@ class Parser(metaclass=_Parser):
return set_ return set_
def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]: def _parse_var_from_options(
for option in options: self, options: OPTIONS_TYPE, raise_unmatched: bool = True
if self._match_text_seq(*option.split(" ")): ) -> t.Optional[exp.Var]:
return exp.var(option) start = self._curr
return None 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: def _parse_as_command(self, start: Token) -> exp.Command:
while self._curr: while self._curr:
@ -5806,14 +5920,12 @@ class Parser(metaclass=_Parser):
return True return True
@t.overload @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 @t.overload
def _replace_columns_with_dots( def _replace_columns_with_dots(
self, this: t.Optional[exp.Expression] self, this: t.Optional[exp.Expression]
) -> t.Optional[exp.Expression]: ) -> t.Optional[exp.Expression]: ...
...
def _replace_columns_with_dots(self, this): def _replace_columns_with_dots(self, this):
if isinstance(this, exp.Dot): if isinstance(this, exp.Dot):
@ -5849,3 +5961,53 @@ class Parser(metaclass=_Parser):
else: else:
column.replace(dot_or_id) column.replace(dot_or_id)
return node 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() OBJECT_IDENTIFIER = auto()
OFFSET = auto() OFFSET = auto()
ON = auto() ON = auto()
ONLY = auto()
OPERATOR = auto() OPERATOR = auto()
ORDER_BY = auto() ORDER_BY = auto()
ORDER_SIBLINGS_BY = auto() ORDER_SIBLINGS_BY = auto()
@ -317,6 +318,7 @@ class TokenType(AutoName):
PIVOT = auto() PIVOT = auto()
PLACEHOLDER = auto() PLACEHOLDER = auto()
PRAGMA = auto() PRAGMA = auto()
PREWHERE = auto()
PRIMARY_KEY = auto() PRIMARY_KEY = auto()
PROCEDURE = auto() PROCEDURE = auto()
PROPERTIES = auto() PROPERTIES = auto()
@ -353,6 +355,7 @@ class TokenType(AutoName):
TOP = auto() TOP = auto()
THEN = auto() THEN = auto()
TRUE = auto() TRUE = auto()
TRUNCATE = auto()
UNCACHE = auto() UNCACHE = auto()
UNION = auto() UNION = auto()
UNNEST = auto() UNNEST = auto()
@ -370,6 +373,7 @@ class TokenType(AutoName):
UNIQUE = auto() UNIQUE = auto()
VERSION_SNAPSHOT = auto() VERSION_SNAPSHOT = auto()
TIMESTAMP_SNAPSHOT = auto() TIMESTAMP_SNAPSHOT = auto()
OPTION = auto()
_ALL_TOKEN_TYPES = list(TokenType) _ALL_TOKEN_TYPES = list(TokenType)
@ -657,6 +661,7 @@ class Tokenizer(metaclass=_Tokenizer):
"DROP": TokenType.DROP, "DROP": TokenType.DROP,
"ELSE": TokenType.ELSE, "ELSE": TokenType.ELSE,
"END": TokenType.END, "END": TokenType.END,
"ENUM": TokenType.ENUM,
"ESCAPE": TokenType.ESCAPE, "ESCAPE": TokenType.ESCAPE,
"EXCEPT": TokenType.EXCEPT, "EXCEPT": TokenType.EXCEPT,
"EXECUTE": TokenType.EXECUTE, "EXECUTE": TokenType.EXECUTE,
@ -752,6 +757,7 @@ class Tokenizer(metaclass=_Tokenizer):
"TEMPORARY": TokenType.TEMPORARY, "TEMPORARY": TokenType.TEMPORARY,
"THEN": TokenType.THEN, "THEN": TokenType.THEN,
"TRUE": TokenType.TRUE, "TRUE": TokenType.TRUE,
"TRUNCATE": TokenType.TRUNCATE,
"UNION": TokenType.UNION, "UNION": TokenType.UNION,
"UNKNOWN": TokenType.UNKNOWN, "UNKNOWN": TokenType.UNKNOWN,
"UNNEST": TokenType.UNNEST, "UNNEST": TokenType.UNNEST,
@ -860,7 +866,6 @@ class Tokenizer(metaclass=_Tokenizer):
"GRANT": TokenType.COMMAND, "GRANT": TokenType.COMMAND,
"OPTIMIZE": TokenType.COMMAND, "OPTIMIZE": TokenType.COMMAND,
"PREPARE": TokenType.COMMAND, "PREPARE": TokenType.COMMAND,
"TRUNCATE": TokenType.COMMAND,
"VACUUM": TokenType.COMMAND, "VACUUM": TokenType.COMMAND,
"USER-DEFINED": TokenType.USERDEFINED, "USER-DEFINED": TokenType.USERDEFINED,
"FOR VERSION": TokenType.VERSION_SNAPSHOT, "FOR VERSION": TokenType.VERSION_SNAPSHOT,
@ -1036,12 +1041,6 @@ class Tokenizer(metaclass=_Tokenizer):
def _text(self) -> str: def _text(self) -> str:
return self.sql[self._start : self._current] 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: def _add(self, token_type: TokenType, text: t.Optional[str] = None) -> None:
self._prev_token_line = self._line self._prev_token_line = self._line
@ -1182,12 +1181,8 @@ class Tokenizer(metaclass=_Tokenizer):
if self._peek.isdigit(): if self._peek.isdigit():
self._advance() self._advance()
elif self._peek == "." and not decimal: elif self._peek == "." and not decimal:
after = self.peek(1) decimal = True
if after.isdigit() or not after.isalpha(): self._advance()
decimal = True
self._advance()
else:
return self._add(TokenType.VAR)
elif self._peek in ("-", "+") and scientific == 1: elif self._peek in ("-", "+") and scientific == 1:
scientific += 1 scientific += 1
self._advance() self._advance()

View file

@ -547,7 +547,7 @@ def move_partitioned_by_to_schema_columns(expression: exp.Expression) -> exp.Exp
prop prop
and prop.this and prop.this
and isinstance(prop.this, exp.Schema) 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( prop_this = exp.Tuple(
expressions=[exp.to_identifier(e.this) for e in prop.this.expressions] 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 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( def preprocess(
transforms: t.List[t.Callable[[exp.Expression], exp.Expression]], transforms: t.List[t.Callable[[exp.Expression], exp.Expression]],
) -> t.Callable[[Generator, exp.Expression], str]: ) -> t.Callable[[Generator, exp.Expression], str]:

2
sqlglotrs/Cargo.lock generated
View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,9 @@ from sqlglot import (
ParseError, ParseError,
TokenError, TokenError,
UnsupportedError, UnsupportedError,
exp,
parse, parse,
parse_one,
transpile, transpile,
) )
from sqlglot.helper import logger as helper_logger from sqlglot.helper import logger as helper_logger
@ -18,6 +20,51 @@ class TestBigQuery(Validator):
maxDiff = None maxDiff = None
def test_bigquery(self): 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 SCHEMA x DEFAULT COLLATE 'en'")
self.validate_identity("CREATE TABLE x (y INT64) DEFAULT COLLATE 'en'") self.validate_identity("CREATE TABLE x (y INT64) DEFAULT COLLATE 'en'")
self.validate_identity("PARSE_JSON('{}', wide_number_mode => 'exact')") 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("LOG(n, b)")
self.validate_identity("SELECT COUNT(x RESPECT NULLS)") 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 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( self.validate_identity(
"SELECT * FROM test QUALIFY a IS DISTINCT FROM b WINDOW c AS (PARTITION BY d)" "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( self.validate_identity(
"""SELECT JSON_EXTRACT_SCALAR('5')""", """SELECT JSON_EXTRACT_SCALAR('5', '$')""" """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( self.validate_identity(
"select array_contains([1, 2, 3], 1)", "select array_contains([1, 2, 3], 1)",
"SELECT EXISTS(SELECT 1 FROM UNNEST([1, 2, 3]) AS _col WHERE _col = 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 JSON '"foo"' AS json_data""",
"""SELECT PARSE_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( self.validate_identity(
"SELECT * FROM UNNEST(x) WITH OFFSET EXCEPT DISTINCT SELECT * FROM UNNEST(y) WITH OFFSET", "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", "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, '\\\\\\((.*)')", 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( self.validate_all(
"TIMESTAMP(x)", "TIMESTAMP(x)",
write={ write={
@ -434,8 +524,8 @@ class TestBigQuery(Validator):
self.validate_all( self.validate_all(
"CREATE OR REPLACE TABLE `a.b.c` COPY `a.b.d`", "CREATE OR REPLACE TABLE `a.b.c` COPY `a.b.d`",
write={ write={
"bigquery": "CREATE OR REPLACE TABLE a.b.c COPY 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", "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("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( self.validate_all(
'SELECT TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE)', 'SELECT TIMESTAMP_ADD(TIMESTAMP "2008-12-25 15:30:00+00", INTERVAL 10 MINUTE)',
write={ write={
@ -566,11 +651,11 @@ class TestBigQuery(Validator):
read={"spark": "select posexplode_outer([])"}, read={"spark": "select posexplode_outer([])"},
) )
self.validate_all( 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={ write={
"": "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",
"bigquery": "SELECT AS STRUCT ARRAY(SELECT AS STRUCT 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': b} FROM x)} FROM z", "duckdb": "SELECT {'y': ARRAY(SELECT {'b': 1} FROM x)} FROM z",
}, },
) )
self.validate_all( self.validate_all(
@ -585,25 +670,9 @@ class TestBigQuery(Validator):
"bigquery": "PARSE_TIMESTAMP('%Y.%m.%d %I:%M:%S%z', x)", "bigquery": "PARSE_TIMESTAMP('%Y.%m.%d %I:%M:%S%z', x)",
}, },
) )
self.validate_all( self.validate_identity(
"CREATE TEMP TABLE foo AS SELECT 1", "CREATE TEMP TABLE foo AS SELECT 1",
write={"bigquery": "CREATE TEMPORARY TABLE foo AS SELECT 1"}, "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)",
},
) )
self.validate_all( self.validate_all(
"REGEXP_CONTAINS('foo', '.*')", "REGEXP_CONTAINS('foo', '.*')",
@ -1088,6 +1157,35 @@ WHERE
self.assertIn("unsupported syntax", cm.output[0]) 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: with self.assertLogs(helper_logger) as cm:
self.validate_identity( self.validate_identity(
"SELECT * FROM t AS t(c1, c2)", "SELECT * FROM t AS t(c1, c2)",

View file

@ -6,6 +6,21 @@ class TestClickhouse(Validator):
dialect = "clickhouse" dialect = "clickhouse"
def test_clickhouse(self): 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") self.validate_identity("SELECT * FROM x LIMIT 1 UNION ALL SELECT * FROM y")
string_types = [ string_types = [
@ -77,6 +92,7 @@ class TestClickhouse(Validator):
self.validate_identity("""SELECT JSONExtractString('{"x": {"y": 1}}', 'x', 'y')""") 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 1 BY a, b")
self.validate_identity("SELECT * FROM table LIMIT 2 OFFSET 1 BY a, b") self.validate_identity("SELECT * FROM table LIMIT 2 OFFSET 1 BY a, b")
self.validate_identity( self.validate_identity(
"SELECT $1$foo$1$", "SELECT $1$foo$1$",
"SELECT 'foo'", "SELECT 'foo'",
@ -134,6 +150,9 @@ class TestClickhouse(Validator):
self.validate_identity( self.validate_identity(
"CREATE MATERIALIZED VIEW test_view (id UInt8) TO db.table1 AS SELECT * FROM test_data" "CREATE MATERIALIZED VIEW test_view (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( self.validate_all(
"SELECT arrayJoin([1,2,3])", "SELECT arrayJoin([1,2,3])",
@ -373,6 +392,7 @@ class TestClickhouse(Validator):
def test_cte(self): def test_cte(self):
self.validate_identity("WITH 'x' AS foo SELECT foo") 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 SUM(bytes) AS foo SELECT foo FROM system.parts")
self.validate_identity("WITH (SELECT foo) AS bar SELECT bar + 5") 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") 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$" "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( self.validate_all(
"CREATE TABLE foo (x INT GENERATED ALWAYS AS (YEAR(y)))", "CREATE TABLE foo (x INT GENERATED ALWAYS AS (YEAR(y)))",
write={ write={

View file

@ -1108,6 +1108,11 @@ class TestDialect(Validator):
) )
def test_order_by(self): 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( self.validate_all(
"SELECT fname, lname, age FROM person ORDER BY age DESC NULLS FIRST, fname ASC NULLS LAST, lname", "SELECT fname, lname, age FROM person ORDER BY age DESC NULLS FIRST, fname ASC NULLS LAST, lname",
write={ write={
@ -1777,7 +1782,7 @@ class TestDialect(Validator):
"CREATE TABLE t (c CHAR, nc NCHAR, v1 VARCHAR, v2 VARCHAR2, nv NVARCHAR, nv2 NVARCHAR2)", "CREATE TABLE t (c CHAR, nc NCHAR, v1 VARCHAR, v2 VARCHAR2, nv NVARCHAR, nv2 NVARCHAR2)",
write={ write={
"duckdb": "CREATE TABLE t (c TEXT, nc TEXT, v1 TEXT, v2 TEXT, nv TEXT, nv2 TEXT)", "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)", "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)", "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)", "sqlite": "CREATE TABLE t (c TEXT, nc TEXT, v1 TEXT, v2 TEXT, nv TEXT, nv2 TEXT)",
@ -2301,3 +2306,9 @@ SELECT
"tsql": UnsupportedError, "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))", "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): def test_identity(self):
self.validate_identity("COALECSE(a, b, c, d)") self.validate_identity("COALECSE(a, b, c, d)")

View file

@ -7,9 +7,14 @@ class TestDuckDB(Validator):
dialect = "duckdb" dialect = "duckdb"
def test_duckdb(self): def test_duckdb(self):
struct_pack = parse_one('STRUCT_PACK("a b" := 1)', read="duckdb") self.validate_all(
self.assertIsInstance(struct_pack.expressions[0].this, exp.Identifier) 'STRUCT_PACK("a b" := 1)',
self.assertEqual(struct_pack.sql(dialect="duckdb"), "{'a b': 1}") write={
"duckdb": "{'a b': 1}",
"spark": "STRUCT(1 AS `a b`)",
"snowflake": "OBJECT_CONSTRUCT('a b', 1)",
},
)
self.validate_all( self.validate_all(
"SELECT SUM(X) OVER (ORDER BY x)", "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"), 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(
self.validate_all(struct_value, write={"presto": UnsupportedError}) "{'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"): for join_type in ("SEMI", "ANTI"):
exists = "EXISTS" if join_type == "SEMI" else "NOT EXISTS" 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("INSERT INTO x BY NAME SELECT 1 AS y")
self.validate_identity("SELECT 1 AS x UNION ALL BY NAME SELECT 2 AS x") self.validate_identity("SELECT 1 AS x UNION ALL BY NAME SELECT 2 AS x")
self.validate_identity("SELECT SUM(x) FILTER (x = 1)", "SELECT SUM(x) FILTER(WHERE x = 1)") self.validate_identity("SELECT SUM(x) FILTER (x = 1)", "SELECT SUM(x) FILTER(WHERE x = 1)")
@ -209,6 +226,10 @@ class TestDuckDB(Validator):
self.validate_identity("FROM (FROM tbl)", "SELECT * FROM (SELECT * FROM tbl)") self.validate_identity("FROM (FROM tbl)", "SELECT * FROM (SELECT * FROM tbl)")
self.validate_identity("FROM tbl", "SELECT * FROM tbl") self.validate_identity("FROM tbl", "SELECT * FROM tbl")
self.validate_identity("x -> '$.family'") 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( self.validate_identity(
"""SELECT '{"foo": [1, 2, 3]}' -> 'foo' -> 0""", """SELECT '{"foo": [1, 2, 3]}' -> 'foo' -> 0""",
"""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): def test_array_index(self):
with self.assertLogs(helper_logger) as cm: with self.assertLogs(helper_logger) as cm:
self.validate_all( self.validate_all(
@ -994,3 +1036,10 @@ class TestDuckDB(Validator):
read={"bigquery": "IS_INF(x)"}, read={"bigquery": "IS_INF(x)"},
write={"bigquery": "IS_INF(x)", "duckdb": "ISINF(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( self.validate_identity(
"SELECT key, value, GROUPING__ID, COUNT(*) FROM T1 GROUP BY key, value WITH ROLLUP" "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( self.validate_all(
"SELECT ${hiveconf:some_var}", "SELECT ${hiveconf:some_var}",
@ -611,12 +614,6 @@ class TestHive(Validator):
"spark": "GET_JSON_OBJECT(x, '$.name')", "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( self.validate_all(
"MAP(a, b, c, d)", "MAP(a, b, c, d)",
read={ 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, INDEX USING BTREE (b))")
self.validate_identity("CREATE TABLE foo (a BIGINT, FULLTEXT INDEX (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("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( self.validate_identity(
"CREATE TABLE `oauth_consumer` (`key` VARCHAR(32) NOT NULL, UNIQUE `OAUTH_CONSUMER_KEY` (`key`))" "CREATE TABLE `oauth_consumer` (`key` VARCHAR(32) NOT NULL, UNIQUE `OAUTH_CONSUMER_KEY` (`key`))"
) )
@ -68,6 +69,26 @@ class TestMySQL(Validator):
self.validate_identity( 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", "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( self.validate_all(
"CREATE TABLE z (a INT) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARACTER SET=utf8 COLLATE=utf8_bin COMMENT='x'", "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)", "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( self.validate_all(
"CREATE TABLE x (id int not null auto_increment, primary key (id))", "CREATE TABLE x (id int not null auto_increment, primary key (id))",
write={ write={
@ -96,33 +111,9 @@ class TestMySQL(Validator):
"sqlite": "CREATE TABLE x (id INTEGER NOT NULL)", "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): 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 DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:00.0000')")
self.validate_identity("SELECT @var1 := 1, @var2") self.validate_identity("SELECT @var1 := 1, @var2")
self.validate_identity("UNLOCK TABLES") 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 sqlglot.errors import UnsupportedError
from tests.dialects.test_dialect import Validator from tests.dialects.test_dialect import Validator
@ -7,11 +7,18 @@ class TestOracle(Validator):
dialect = "oracle" dialect = "oracle"
def test_oracle(self): def test_oracle(self):
self.validate_identity("REGEXP_REPLACE('source', 'search')") self.validate_all(
parse_one("ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol", dialect="oracle").assert_is( "SELECT CONNECT_BY_ROOT x y",
exp.AlterTable 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("TIMESTAMP(3) WITH TIME ZONE")
self.validate_identity("CURRENT_TIMESTAMP(precision)") self.validate_identity("CURRENT_TIMESTAMP(precision)")
self.validate_identity("ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol") 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_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( self.validate_all(
"SELECT TO_CHAR(TIMESTAMP '1999-12-01 10:00:00')", "SELECT TO_CHAR(TIMESTAMP '1999-12-01 10:00:00')",
write={ write={

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