1
0
Fork 0

Merging upstream version 25.31.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-13 21:57:20 +01:00
parent 94fd84e2b9
commit 4c76f76a29
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
68 changed files with 58911 additions and 55752 deletions

View file

@ -1,6 +1,100 @@
Changelog
=========
## [v25.31.3] - 2024-11-17
### :sparkles: New Features
- [`835e717`](https://github.com/tobymao/sqlglot/commit/835e71795f994599dbc19f1a5969b464154926e1) - **clickhouse**: transform function support *(PR [#4408](https://github.com/tobymao/sqlglot/pull/4408) by [@GaliFFun](https://github.com/GaliFFun))*
### :bug: Bug Fixes
- [`0479743`](https://github.com/tobymao/sqlglot/commit/047974393cebbddbbfb878071d159a3e538b0e4d) - **snowflake**: cast to TimeToStr arg to TIMESTAMP more conservatively *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v25.31.2] - 2024-11-17
### :bug: Bug Fixes
- [`d851269`](https://github.com/tobymao/sqlglot/commit/d851269780c7f0a0c756289c3dea9b1aa58d2a69) - use existing aliases in DISTINCT ON elimination, if any *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v25.31.1] - 2024-11-17
### :sparkles: New Features
- [`b00d857`](https://github.com/tobymao/sqlglot/commit/b00d857cd8a6d2452c2170077cbfa82352f708dd) - add support for specifying column in row_number function *(PR [#4406](https://github.com/tobymao/sqlglot/pull/4406) by [@GaliFFun](https://github.com/GaliFFun))*
### :bug: Bug Fixes
- [`0e46cc7`](https://github.com/tobymao/sqlglot/commit/0e46cc7fa2d80ba4e92182b3fa5f1075a63f4754) - refactor DISTINCT ON elimination transformation *(PR [#4407](https://github.com/tobymao/sqlglot/pull/4407) by [@georgesittas](https://github.com/georgesittas))*
## [v25.31.0] - 2024-11-16
### :boom: BREAKING CHANGES
- due to [`f4abfd5`](https://github.com/tobymao/sqlglot/commit/f4abfd59b8255cf8c39bf51028ee5f6ed704927f) - Support FORMAT_TIMESTAMP *(PR [#4383](https://github.com/tobymao/sqlglot/pull/4383) by [@VaggelisD](https://github.com/VaggelisD))*:
Support FORMAT_TIMESTAMP (#4383)
- due to [`45eef60`](https://github.com/tobymao/sqlglot/commit/45eef600064ad024b34e32e7acc3aca409fbd9c4) - use select star when eliminating distinct on *(PR [#4401](https://github.com/tobymao/sqlglot/pull/4401) by [@agrigoroi-palantir](https://github.com/agrigoroi-palantir))*:
use select star when eliminating distinct on (#4401)
### :sparkles: New Features
- [`72ffdcb`](https://github.com/tobymao/sqlglot/commit/72ffdcb631bf7afdeda2ce96911442a94b7f11eb) - **bigquery**: Add parsing support for STRPOS(...) *(PR [#4378](https://github.com/tobymao/sqlglot/pull/4378) by [@VaggelisD](https://github.com/VaggelisD))*
- [`e7b67e0`](https://github.com/tobymao/sqlglot/commit/e7b67e0c280179188ce1bca650735978b758dca1) - **bigquery**: Support MAKE_INTERVAL *(PR [#4384](https://github.com/tobymao/sqlglot/pull/4384) by [@VaggelisD](https://github.com/VaggelisD))*
- [`37c4809`](https://github.com/tobymao/sqlglot/commit/37c4809dfda48224fd982ea8a48d3dbc5c17f9ae) - **bigquery**: Support INT64(...) *(PR [#4391](https://github.com/tobymao/sqlglot/pull/4391) by [@VaggelisD](https://github.com/VaggelisD))*
- [`9694999`](https://github.com/tobymao/sqlglot/commit/96949999d394e27df8b0287a14e9ac82d52bc0f9) - Add support for CONTAINS(...) *(PR [#4399](https://github.com/tobymao/sqlglot/pull/4399) by [@VaggelisD](https://github.com/VaggelisD))*
### :bug: Bug Fixes
- [`f4abfd5`](https://github.com/tobymao/sqlglot/commit/f4abfd59b8255cf8c39bf51028ee5f6ed704927f) - **bigquery**: Support FORMAT_TIMESTAMP *(PR [#4383](https://github.com/tobymao/sqlglot/pull/4383) by [@VaggelisD](https://github.com/VaggelisD))*
- [`bb46ee3`](https://github.com/tobymao/sqlglot/commit/bb46ee33d481a888882cbbb26a9240dd2dbb10ee) - **parser**: Parse exp.Column for DROP COLUMN *(PR [#4390](https://github.com/tobymao/sqlglot/pull/4390) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4388](https://github.com/tobymao/sqlglot/issues/4388) opened by [@AhlamHani](https://github.com/AhlamHani)*
- [`79f6783`](https://github.com/tobymao/sqlglot/commit/79f67830d7d3ba92bff91eeb95b4dc8bdfa6c44e) - **snowflake**: Wrap DIV0 operands if they're binary expressions *(PR [#4393](https://github.com/tobymao/sqlglot/pull/4393) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4392](https://github.com/tobymao/sqlglot/issues/4392) opened by [@diogo-fernan](https://github.com/diogo-fernan)*
- [`647b98d`](https://github.com/tobymao/sqlglot/commit/647b98d84643b88a41218fb67f6a2bd83ca4c702) - **starrocks**: Add RESERVED_KEYWORDS specific to starrocks *(PR [#4402](https://github.com/tobymao/sqlglot/pull/4402) by [@notexistence](https://github.com/notexistence))*
- [`45eef60`](https://github.com/tobymao/sqlglot/commit/45eef600064ad024b34e32e7acc3aca409fbd9c4) - use select star when eliminating distinct on *(PR [#4401](https://github.com/tobymao/sqlglot/pull/4401) by [@agrigoroi-palantir](https://github.com/agrigoroi-palantir))*
### :recycle: Refactors
- [`a3af2af`](https://github.com/tobymao/sqlglot/commit/a3af2af3a893dfd6c6946b732aa086d1f1d91570) - attach stamement comments consistently *(PR [#4377](https://github.com/tobymao/sqlglot/pull/4377) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4376](https://github.com/tobymao/sqlglot/issues/4376) opened by [@YieldRay](https://github.com/YieldRay)*
### :wrench: Chores
- [`858c5b1`](https://github.com/tobymao/sqlglot/commit/858c5b1a43f74e11b8c357986c78b5068792b3af) - improve contribution guide *(PR [#4379](https://github.com/tobymao/sqlglot/pull/4379) by [@georgesittas](https://github.com/georgesittas))*
- [`160e688`](https://github.com/tobymao/sqlglot/commit/160e6883225cd6ad41a218213f73aa9f91b5fc5e) - fix relative benchmark import, comment out sqltree *(PR [#4403](https://github.com/tobymao/sqlglot/pull/4403) by [@georgesittas](https://github.com/georgesittas))*
- [`8d78add`](https://github.com/tobymao/sqlglot/commit/8d78addccaaffa4ea2dcfe1de002f8a653f137b7) - bump PYO3 to v"0.22.6" *(PR [#4400](https://github.com/tobymao/sqlglot/pull/4400) by [@MartinSahlen](https://github.com/MartinSahlen))*
- [`f78e755`](https://github.com/tobymao/sqlglot/commit/f78e755adaf52823642d2b0e1cae54da835ec653) - bump sqlglotrs to v0.2.14 *(commit by [@georgesittas](https://github.com/georgesittas))*
## [v25.30.0] - 2024-11-11
### :boom: BREAKING CHANGES
- due to [`60625ea`](https://github.com/tobymao/sqlglot/commit/60625eae34deb6a6fc36c0f3996f1281eae0ef6f) - Fix STRUCT cast generation *(PR [#4366](https://github.com/tobymao/sqlglot/pull/4366) by [@VaggelisD](https://github.com/VaggelisD))*:
Fix STRUCT cast generation (#4366)
### :sparkles: New Features
- [`87ab8fe`](https://github.com/tobymao/sqlglot/commit/87ab8fe9cc4d6d060d8fe8a9c3faf8c47c2c9ed6) - **spark, bigquery**: Add support for UNIX_SECONDS(...) *(PR [#4350](https://github.com/tobymao/sqlglot/pull/4350) by [@VaggelisD](https://github.com/VaggelisD))*
- [`42da638`](https://github.com/tobymao/sqlglot/commit/42da63812ed489d1d8bbef0fc14c7dfa5ce57b7a) - **bigquery**: Support JSON_VALUE_ARRAY(...) *(PR [#4356](https://github.com/tobymao/sqlglot/pull/4356) by [@VaggelisD](https://github.com/VaggelisD))*
- [`e337a42`](https://github.com/tobymao/sqlglot/commit/e337a42dd56f5358e617750e7a70a0d4b7eab3f9) - **bigquery**: Parse REGEXP_SUBSTR as exp.RegexpExtract *(PR [#4358](https://github.com/tobymao/sqlglot/pull/4358) by [@VaggelisD](https://github.com/VaggelisD))*
- [`602dbf8`](https://github.com/tobymao/sqlglot/commit/602dbf84ce23f41fba6a87db70ecec6113044bac) - Support REGEXP_EXTRACT_ALL *(PR [#4359](https://github.com/tobymao/sqlglot/pull/4359) by [@VaggelisD](https://github.com/VaggelisD))*
- [`27a44a2`](https://github.com/tobymao/sqlglot/commit/27a44a22ff78cc35e8ab7c91b94311ef93d86c5a) - improve Levenshtein expression transpilation *(PR [#4360](https://github.com/tobymao/sqlglot/pull/4360) by [@krzysztof-kwitt](https://github.com/krzysztof-kwitt))*
- [`79c675a`](https://github.com/tobymao/sqlglot/commit/79c675a49fb44a6a7a97ea0de79822d8571724be) - **bigquery**: Support JSON_QUERY_ARRAY & JSON_EXTRACT_ARRAY *(PR [#4361](https://github.com/tobymao/sqlglot/pull/4361) by [@VaggelisD](https://github.com/VaggelisD))*
- [`57722db`](https://github.com/tobymao/sqlglot/commit/57722db90394d9a102c0e76a3e4d32a9f72f9ff9) - optionally wrap connectors when using builders *(PR [#4369](https://github.com/tobymao/sqlglot/pull/4369) by [@georgesittas](https://github.com/georgesittas))*
- :arrow_lower_right: *addresses issue [#4362](https://github.com/tobymao/sqlglot/issues/4362) opened by [@gabrielteotonio](https://github.com/gabrielteotonio)*
- :arrow_lower_right: *addresses issue [#4367](https://github.com/tobymao/sqlglot/issues/4367) opened by [@gabrielteotonio](https://github.com/gabrielteotonio)*
### :bug: Bug Fixes
- [`eb8e2fe`](https://github.com/tobymao/sqlglot/commit/eb8e2fe3ab3fb4b88f72843a5bd21f4a3c1d895c) - bubble up comments in qualified column refs fixes [#4353](https://github.com/tobymao/sqlglot/pull/4353) *(commit by [@georgesittas](https://github.com/georgesittas))*
- [`efcbfdb`](https://github.com/tobymao/sqlglot/commit/efcbfdb67b12853581fbfc0d4c4a450c0281849b) - **clickhouse**: Generate exp.Median as lowercase *(PR [#4355](https://github.com/tobymao/sqlglot/pull/4355) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4354](https://github.com/tobymao/sqlglot/issues/4354) opened by [@cpcloud](https://github.com/cpcloud)*
- [`60625ea`](https://github.com/tobymao/sqlglot/commit/60625eae34deb6a6fc36c0f3996f1281eae0ef6f) - **duckdb**: Fix STRUCT cast generation *(PR [#4366](https://github.com/tobymao/sqlglot/pull/4366) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4365](https://github.com/tobymao/sqlglot/issues/4365) opened by [@NickCrews](https://github.com/NickCrews)*
- [`a665030`](https://github.com/tobymao/sqlglot/commit/a665030323b200f3bed241bb928993b9807c4100) - safe removal while iterating expression list for multiple UNNEST expressions *(PR [#4364](https://github.com/tobymao/sqlglot/pull/4364) by [@gauravsagar483](https://github.com/gauravsagar483))*
- [`a71cee4`](https://github.com/tobymao/sqlglot/commit/a71cee4b4eafad9988b945c69dc75583ae105ec7) - Transpilation of exp.ArraySize from Postgres (read) *(PR [#4370](https://github.com/tobymao/sqlglot/pull/4370) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4368](https://github.com/tobymao/sqlglot/issues/4368) opened by [@dor-bernstein](https://github.com/dor-bernstein)*
- [`702fe31`](https://github.com/tobymao/sqlglot/commit/702fe318dadbe6cb83676e2a23ee830774697bb0) - Remove flaky timing test *(PR [#4371](https://github.com/tobymao/sqlglot/pull/4371) by [@VaggelisD](https://github.com/VaggelisD))*
- [`4d3904e`](https://github.com/tobymao/sqlglot/commit/4d3904e8906f0573f3352ad82282ea09c571daa8) - **spark**: Support DB's TIMESTAMP_DIFF *(PR [#4373](https://github.com/tobymao/sqlglot/pull/4373) by [@VaggelisD](https://github.com/VaggelisD))*
- :arrow_lower_right: *fixes issue [#4372](https://github.com/tobymao/sqlglot/issues/4372) opened by [@nikmalviya](https://github.com/nikmalviya)*
- [`060ecfc`](https://github.com/tobymao/sqlglot/commit/060ecfc75fd8a07ffbc19f34959155a0fce317b6) - don't generate comments in table_name *(PR [#4375](https://github.com/tobymao/sqlglot/pull/4375) by [@georgesittas](https://github.com/georgesittas))*
### :wrench: Chores
- [`e19fb62`](https://github.com/tobymao/sqlglot/commit/e19fb620dbe6e405518aee381183e4640b638aa4) - improve error handling for unnest_to_explode *(PR [#4339](https://github.com/tobymao/sqlglot/pull/4339) by [@gauravsagar483](https://github.com/gauravsagar483))*
## [v25.29.0] - 2024-11-05
### :boom: BREAKING CHANGES
- due to [`e92904e`](https://github.com/tobymao/sqlglot/commit/e92904e61ab3b14fe18d472df19311f9b014f6cc) - Transpile ANY to EXISTS *(PR [#4305](https://github.com/tobymao/sqlglot/pull/4305) by [@VaggelisD](https://github.com/VaggelisD))*:
@ -5214,3 +5308,8 @@ Changelog
[v25.27.0]: https://github.com/tobymao/sqlglot/compare/v25.26.0...v25.27.0
[v25.28.0]: https://github.com/tobymao/sqlglot/compare/v25.27.0...v25.28.0
[v25.29.0]: https://github.com/tobymao/sqlglot/compare/v25.28.0...v25.29.0
[v25.30.0]: https://github.com/tobymao/sqlglot/compare/v25.29.0...v25.30.0
[v25.31.0]: https://github.com/tobymao/sqlglot/compare/v25.30.0...v25.31.0
[v25.31.1]: https://github.com/tobymao/sqlglot/compare/v25.31.0...v25.31.1
[v25.31.2]: https://github.com/tobymao/sqlglot/compare/v25.31.1...v25.31.2
[v25.31.3]: https://github.com/tobymao/sqlglot/compare/v25.31.2...v25.31.3

View file

@ -9,30 +9,45 @@ easy and transparent as possible, whether it's:
- Proposing new features
## We develop with Github
We use github to host code, to track issues and feature requests, as well as accept pull requests.
## Finding tasks to work on
When the core SQLGlot team does not plan to work on an issue, it is usually closed as "not planned". This may happen
when a request is exceptionally difficult to address, or because the team deems that it shouldn't be prioritized.
These issues can be a good starting point when looking for tasks to work on. Simply filter the issue list to fetch
the closed issues and then search for those marked as "not planned". If the scope of an issue is not clear or you
need guidance, feel free to ask for clarifications.
Before taking on a task, consider studying the [AST primer](https://github.com/tobymao/sqlglot/blob/main/posts/ast_primer.md) and the [onboarding document](https://github.com/tobymao/sqlglot/blob/main/posts/onboarding.md).
## Submitting code changes
Pull requests are the best way to propose changes to the codebase. We actively welcome your pull requests:
Please keep PR's small and do your best to follow the conventions of the project. If you have a feature that requires a lot of code changes,
please reach out to us on [Slack](https://tobikodata.com/slack) before making a PR. This will increase the chances of your PR getting in.
Pull requests are the best way to propose changes to the codebase, and we actively welcome them.
1. Fork the repo and create your branch from `main`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite & linter [checks](https://github.com/tobymao/sqlglot/blob/main/README.md#run-tests-and-lint) pass.
5. Issue that pull request and wait for it to be reviewed by a maintainer or contributor!
Pull requests should be small and they need to follow the conventions of the project. For features that require
many changes, please reach out to us on [Slack](https://tobikodata.com/slack) before making a request, in order
to share any relevant context and increase its chances of getting merged.
1. Fork the repo and create your branch from `main`
2. If you've added code with non-trivial changes, add tests
3. If you've changed APIs, update the documentation (docstrings)
4. Ensure the test suite & linter [checks](https://github.com/tobymao/sqlglot/blob/main/README.md#run-tests-and-lint) pass
5. Issue that pull request and wait for it to be reviewed by a maintainer or contributor
Note: make sure to follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) guidelines when creating a PR.
## Report bugs using Github's [issues](https://github.com/tobymao/sqlglot/issues)
We use GitHub issues to track public bugs. Report a bug by opening a new issue.
**Great Bug Reports** tend to have:
- A quick summary and/or background
- Steps to reproduce
- Be specific!
- Be specific
- Give sample code if you can
- What you expected would happen
- What actually happens
@ -40,12 +55,15 @@ We use GitHub issues to track public bugs. Report a bug by opening a new issue.
- References (e.g. documentation pages related to the issue)
## Start a discussion using Github's [discussions](https://github.com/tobymao/sqlglot/discussions)
[We use GitHub discussions](https://github.com/tobymao/sqlglot/discussions/190) to discuss about the current state
of the code. If you want to propose a new feature, this is the right place to do it! Just start a discussion, and
of the code. If you want to propose a new feature, this is the right place to do it. Just start a discussion, and
let us know why you think this feature would be a good addition to SQLGlot (by possibly including some usage examples).
## [License](https://github.com/tobymao/sqlglot/blob/main/LICENSE)
By contributing, you agree that your contributions will be licensed under its MIT License.
## References
This document was adapted from [briandk's template](https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62).

View file

@ -1,6 +1,6 @@
import collections.abc
from benchmarks.helpers import ascii_table
from helpers import ascii_table
# moz_sql_parser 3.10 compatibility
collections.Iterable = collections.abc.Iterable
@ -12,7 +12,7 @@ import numpy as np
# import moz_sql_parser
# import sqloxide
# import sqlparse
import sqltree
# import sqltree
import sqlglot
@ -203,7 +203,7 @@ libs = [
"sqlglot",
"sqlglotrs",
# "sqlfluff",
"sqltree",
# "sqltree",
# "sqlparse",
# "moz_sql_parser",
# "sqloxide",

View file

@ -1,7 +1,7 @@
import typing as t
from argparse import ArgumentParser
from benchmarks.helpers import ascii_table
from helpers import ascii_table
from sqlglot.optimizer import optimize
from sqlglot import parse_one
from tests.helpers import load_sql_fixture_pairs, TPCH_SCHEMA, TPCDS_SCHEMA

File diff suppressed because one or more lines are too long

View file

@ -76,8 +76,8 @@
</span><span id="L-12"><a href="#L-12"><span class="linenos">12</span></a><span class="n">__version_tuple__</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-13"><a href="#L-13"><span class="linenos">13</span></a><span class="n">version_tuple</span><span class="p">:</span> <span class="n">VERSION_TUPLE</span>
</span><span id="L-14"><a href="#L-14"><span class="linenos">14</span></a>
</span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;25.29.0&#39;</span>
</span><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mi">29</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span><span id="L-15"><a href="#L-15"><span class="linenos">15</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;25.31.3&#39;</span>
</span><span id="L-16"><a href="#L-16"><span class="linenos">16</span></a><span class="n">__version_tuple__</span> <span class="o">=</span> <span class="n">version_tuple</span> <span class="o">=</span> <span class="p">(</span><span class="mi">25</span><span class="p">,</span> <span class="mi">31</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</span></pre></div>
@ -97,7 +97,7 @@
<section id="version">
<div class="attr variable">
<span class="name">version</span><span class="annotation">: str</span> =
<span class="default_value">&#39;25.29.0&#39;</span>
<span class="default_value">&#39;25.31.3&#39;</span>
</div>
@ -109,7 +109,7 @@
<section id="version_tuple">
<div class="attr variable">
<span class="name">version_tuple</span><span class="annotation">: object</span> =
<span class="default_value">(25, 29, 0)</span>
<span class="default_value">(25, 31, 3)</span>
</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -737,7 +737,9 @@ Default: True</li>
<dd id="RisingWave.Generator.PAD_FILL_PATTERN_IS_REQUIRED" class="variable"><a href="../generator.html#Generator.PAD_FILL_PATTERN_IS_REQUIRED">PAD_FILL_PATTERN_IS_REQUIRED</a></dd>
<dd id="RisingWave.Generator.SUPPORTS_EXPLODING_PROJECTIONS" class="variable"><a href="../generator.html#Generator.SUPPORTS_EXPLODING_PROJECTIONS">SUPPORTS_EXPLODING_PROJECTIONS</a></dd>
<dd id="RisingWave.Generator.SUPPORTS_CONVERT_TIMEZONE" class="variable"><a href="../generator.html#Generator.SUPPORTS_CONVERT_TIMEZONE">SUPPORTS_CONVERT_TIMEZONE</a></dd>
<dd id="RisingWave.Generator.SUPPORTS_UNIX_SECONDS" class="variable"><a href="../generator.html#Generator.SUPPORTS_UNIX_SECONDS">SUPPORTS_UNIX_SECONDS</a></dd>
<dd id="RisingWave.Generator.PARSE_JSON_NAME" class="variable"><a href="../generator.html#Generator.PARSE_JSON_NAME">PARSE_JSON_NAME</a></dd>
<dd id="RisingWave.Generator.ARRAY_SIZE_NAME" class="variable"><a href="../generator.html#Generator.ARRAY_SIZE_NAME">ARRAY_SIZE_NAME</a></dd>
<dd id="RisingWave.Generator.TIME_PART_SINGULARS" class="variable"><a href="../generator.html#Generator.TIME_PART_SINGULARS">TIME_PART_SINGULARS</a></dd>
<dd id="RisingWave.Generator.TOKEN_MAPPING" class="variable"><a href="../generator.html#Generator.TOKEN_MAPPING">TOKEN_MAPPING</a></dd>
<dd id="RisingWave.Generator.STRUCT_DELIMITER" class="variable"><a href="../generator.html#Generator.STRUCT_DELIMITER">STRUCT_DELIMITER</a></dd>
@ -1065,6 +1067,7 @@ Default: True</li>
<dd id="RisingWave.Generator.toarray_sql" class="function"><a href="../generator.html#Generator.toarray_sql">toarray_sql</a></dd>
<dd id="RisingWave.Generator.tsordstotime_sql" class="function"><a href="../generator.html#Generator.tsordstotime_sql">tsordstotime_sql</a></dd>
<dd id="RisingWave.Generator.tsordstotimestamp_sql" class="function"><a href="../generator.html#Generator.tsordstotimestamp_sql">tsordstotimestamp_sql</a></dd>
<dd id="RisingWave.Generator.tsordstodatetime_sql" class="function"><a href="../generator.html#Generator.tsordstodatetime_sql">tsordstodatetime_sql</a></dd>
<dd id="RisingWave.Generator.tsordstodate_sql" class="function"><a href="../generator.html#Generator.tsordstodate_sql">tsordstodate_sql</a></dd>
<dd id="RisingWave.Generator.unixdate_sql" class="function"><a href="../generator.html#Generator.unixdate_sql">unixdate_sql</a></dd>
<dd id="RisingWave.Generator.lastday_sql" class="function"><a href="../generator.html#Generator.lastday_sql">lastday_sql</a></dd>
@ -1108,6 +1111,8 @@ Default: True</li>
<dd id="RisingWave.Generator.string_sql" class="function"><a href="../generator.html#Generator.string_sql">string_sql</a></dd>
<dd id="RisingWave.Generator.median_sql" class="function"><a href="../generator.html#Generator.median_sql">median_sql</a></dd>
<dd id="RisingWave.Generator.overflowtruncatebehavior_sql" class="function"><a href="../generator.html#Generator.overflowtruncatebehavior_sql">overflowtruncatebehavior_sql</a></dd>
<dd id="RisingWave.Generator.unixseconds_sql" class="function"><a href="../generator.html#Generator.unixseconds_sql">unixseconds_sql</a></dd>
<dd id="RisingWave.Generator.arraysize_sql" class="function"><a href="../generator.html#Generator.arraysize_sql">arraysize_sql</a></dd>
</div>
<div><dt><a href="postgres.html#Postgres.Generator">sqlglot.dialects.postgres.Postgres.Generator</a></dt>
@ -1129,6 +1134,7 @@ Default: True</li>
<dd id="RisingWave.Generator.COPY_HAS_INTO_KEYWORD" class="variable"><a href="postgres.html#Postgres.Generator.COPY_HAS_INTO_KEYWORD">COPY_HAS_INTO_KEYWORD</a></dd>
<dd id="RisingWave.Generator.ARRAY_CONCAT_IS_VAR_LEN" class="variable"><a href="postgres.html#Postgres.Generator.ARRAY_CONCAT_IS_VAR_LEN">ARRAY_CONCAT_IS_VAR_LEN</a></dd>
<dd id="RisingWave.Generator.SUPPORTS_MEDIAN" class="variable"><a href="postgres.html#Postgres.Generator.SUPPORTS_MEDIAN">SUPPORTS_MEDIAN</a></dd>
<dd id="RisingWave.Generator.ARRAY_SIZE_DIM_REQUIRED" class="variable"><a href="postgres.html#Postgres.Generator.ARRAY_SIZE_DIM_REQUIRED">ARRAY_SIZE_DIM_REQUIRED</a></dd>
<dd id="RisingWave.Generator.SUPPORTED_JSON_PATH_PARTS" class="variable"><a href="postgres.html#Postgres.Generator.SUPPORTED_JSON_PATH_PARTS">SUPPORTED_JSON_PATH_PARTS</a></dd>
<dd id="RisingWave.Generator.TYPE_MAPPING" class="variable"><a href="postgres.html#Postgres.Generator.TYPE_MAPPING">TYPE_MAPPING</a></dd>
<dd id="RisingWave.Generator.TRANSFORMS" class="variable"><a href="postgres.html#Postgres.Generator.TRANSFORMS">TRANSFORMS</a></dd>

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

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

View file

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

File diff suppressed because one or more lines are too long

View file

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

View file

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9075,7 +9075,7 @@
<div class="attr variable">
<span class="name">COMMANDS</span> =
<input id="Tokenizer.COMMANDS-view-value" class="view-value-toggle-state" type="checkbox" aria-hidden="true" tabindex="-1">
<label class="view-value-button pdoc-button" for="Tokenizer.COMMANDS-view-value"></label><span class="default_value">{&lt;<a href="#TokenType.SHOW">TokenType.SHOW</a>: &#39;SHOW&#39;&gt;, &lt;<a href="#TokenType.FETCH">TokenType.FETCH</a>: &#39;FETCH&#39;&gt;, &lt;<a href="#TokenType.EXECUTE">TokenType.EXECUTE</a>: &#39;EXECUTE&#39;&gt;, &lt;<a href="#TokenType.COMMAND">TokenType.COMMAND</a>: &#39;COMMAND&#39;&gt;, &lt;<a href="#TokenType.RENAME">TokenType.RENAME</a>: &#39;RENAME&#39;&gt;}</span>
<label class="view-value-button pdoc-button" for="Tokenizer.COMMANDS-view-value"></label><span class="default_value">{&lt;<a href="#TokenType.SHOW">TokenType.SHOW</a>: &#39;SHOW&#39;&gt;, &lt;<a href="#TokenType.EXECUTE">TokenType.EXECUTE</a>: &#39;EXECUTE&#39;&gt;, &lt;<a href="#TokenType.FETCH">TokenType.FETCH</a>: &#39;FETCH&#39;&gt;, &lt;<a href="#TokenType.COMMAND">TokenType.COMMAND</a>: &#39;COMMAND&#39;&gt;, &lt;<a href="#TokenType.RENAME">TokenType.RENAME</a>: &#39;RENAME&#39;&gt;}</span>
</div>

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ from sqlglot.dialects.dialect import (
timestrtotime_sql,
ts_or_ds_add_cast,
unit_to_var,
str_position_sql,
)
from sqlglot.helper import seq_get, split_num_words
from sqlglot.tokens import TokenType
@ -211,7 +212,7 @@ def _build_time(args: t.List) -> exp.Func:
def _build_datetime(args: t.List) -> exp.Func:
if len(args) == 1:
return exp.TsOrDsToTimestamp.from_arg_list(args)
return exp.TsOrDsToDatetime.from_arg_list(args)
if len(args) == 2:
return exp.Datetime.from_arg_list(args)
return exp.TimestampFromParts.from_arg_list(args)
@ -304,6 +305,25 @@ def _build_levenshtein(args: t.List) -> exp.Levenshtein:
)
def _build_format_time(expr_type: t.Type[exp.Expression]) -> t.Callable[[t.List], exp.TimeToStr]:
def _builder(args: t.List) -> exp.TimeToStr:
return exp.TimeToStr(this=expr_type(this=seq_get(args, 1)), format=seq_get(args, 0))
return _builder
def _build_contains_substring(args: t.List) -> exp.Contains | exp.Anonymous:
if len(args) == 3:
return exp.Anonymous(this="CONTAINS_SUBSTRING", expressions=args)
# Lowercase the operands in case of transpilation, as exp.Contains
# is case-sensitive on other dialects
this = exp.Lower(this=seq_get(args, 0))
expr = exp.Lower(this=seq_get(args, 1))
return exp.Contains(this=this, expression=expr)
class BigQuery(Dialect):
WEEK_OFFSET = -1
UNNEST_COLUMN_ONLY = True
@ -449,6 +469,7 @@ class BigQuery(Dialect):
FUNCTIONS = {
**parser.Parser.FUNCTIONS,
"CONTAINS_SUBSTRING": _build_contains_substring,
"DATE": _build_date,
"DATE_ADD": build_date_delta_with_interval(exp.DateAdd),
"DATE_SUB": build_date_delta_with_interval(exp.DateSub),
@ -462,9 +483,7 @@ class BigQuery(Dialect):
"DATETIME_SUB": build_date_delta_with_interval(exp.DatetimeSub),
"DIV": binary_from_function(exp.IntDiv),
"EDIT_DISTANCE": _build_levenshtein,
"FORMAT_DATE": lambda args: exp.TimeToStr(
this=exp.TsOrDsToDate(this=seq_get(args, 1)), format=seq_get(args, 0)
),
"FORMAT_DATE": _build_format_time(exp.TsOrDsToDate),
"GENERATE_ARRAY": exp.GenerateSeries.from_arg_list,
"JSON_EXTRACT_SCALAR": _build_extract_json_with_default_path(exp.JSONExtractScalar),
"JSON_EXTRACT_ARRAY": _build_extract_json_with_default_path(exp.JSONExtractArray),
@ -492,6 +511,7 @@ class BigQuery(Dialect):
this=seq_get(args, 0),
expression=seq_get(args, 1) or exp.Literal.string(","),
),
"STRPOS": exp.StrPosition.from_arg_list,
"TIME": _build_time,
"TIME_ADD": build_date_delta_with_interval(exp.TimeAdd),
"TIME_SUB": build_date_delta_with_interval(exp.TimeSub),
@ -506,14 +526,14 @@ class BigQuery(Dialect):
),
"TIMESTAMP_SECONDS": lambda args: exp.UnixToTime(this=seq_get(args, 0)),
"TO_JSON_STRING": exp.JSONFormat.from_arg_list,
"FORMAT_DATETIME": lambda args: exp.TimeToStr(
this=exp.TsOrDsToTimestamp(this=seq_get(args, 1)), format=seq_get(args, 0)
),
"FORMAT_DATETIME": _build_format_time(exp.TsOrDsToDatetime),
"FORMAT_TIMESTAMP": _build_format_time(exp.TsOrDsToTimestamp),
}
FUNCTION_PARSERS = {
**parser.Parser.FUNCTION_PARSERS,
"ARRAY": lambda self: self.expression(exp.Array, expressions=[self._parse_statement()]),
"MAKE_INTERVAL": lambda self: self._parse_make_interval(),
}
FUNCTION_PARSERS.pop("TRIM")
@ -744,6 +764,26 @@ class BigQuery(Dialect):
return unnest
def _parse_make_interval(self):
expr = exp.MakeInterval()
for arg_key in expr.arg_types:
value = self._parse_lambda()
if not value:
break
# Non-named arguments are filled sequentially, (optionally) followed by named arguments
# that can appear in any order e.g MAKE_INTERVAL(1, minute => 5, day => 2)
if isinstance(value, exp.Kwarg):
arg_key = value.this.name
expr.set(arg_key, value)
self._match(TokenType.COMMA)
return expr
class Generator(generator.Generator):
INTERVAL_ALLOWS_PLURAL_FORM = False
JOIN_HINTS = False
@ -809,6 +849,7 @@ class BigQuery(Dialect):
exp.If: if_sql(false_value="NULL"),
exp.ILike: no_ilike_sql,
exp.IntDiv: rename_func("DIV"),
exp.Int64: rename_func("INT64"),
exp.JSONFormat: rename_func("TO_JSON_STRING"),
exp.Levenshtein: _levenshtein_sql,
exp.Max: max_or_greatest,
@ -845,6 +886,7 @@ class BigQuery(Dialect):
"DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC"
),
exp.String: rename_func("STRING"),
exp.StrPosition: str_position_sql,
exp.StrToDate: _str_to_datetime_sql,
exp.StrToTime: _str_to_datetime_sql,
exp.TimeAdd: date_add_interval_sql("TIME", "ADD"),
@ -859,7 +901,8 @@ class BigQuery(Dialect):
exp.TsOrDsAdd: _ts_or_ds_add_sql,
exp.TsOrDsDiff: _ts_or_ds_diff_sql,
exp.TsOrDsToTime: rename_func("TIME"),
exp.TsOrDsToTimestamp: rename_func("DATETIME"),
exp.TsOrDsToDatetime: rename_func("DATETIME"),
exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"),
exp.Unhex: rename_func("FROM_HEX"),
exp.UnixDate: rename_func("UNIX_DATE"),
exp.UnixToTime: _unix_to_time_sql,
@ -1048,16 +1091,20 @@ class BigQuery(Dialect):
return super().table_parts(expression)
def timetostr_sql(self, expression: exp.TimeToStr) -> str:
if isinstance(expression.this, exp.TsOrDsToTimestamp):
this = expression.this
if isinstance(this, exp.TsOrDsToDatetime):
func_name = "FORMAT_DATETIME"
elif isinstance(this, exp.TsOrDsToTimestamp):
func_name = "FORMAT_TIMESTAMP"
else:
func_name = "FORMAT_DATE"
this = (
expression.this
if isinstance(expression.this, (exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
time_expr = (
this
if isinstance(this, (exp.TsOrDsToDatetime, exp.TsOrDsToTimestamp, exp.TsOrDsToDate))
else expression
)
return self.func(func_name, self.format_time(expression), this.this)
return self.func(func_name, self.format_time(expression), time_expr.this)
def eq_sql(self, expression: exp.EQ) -> str:
# Operands of = cannot be NULL in BigQuery
@ -1119,3 +1166,13 @@ class BigQuery(Dialect):
if expression.name == "TIMESTAMP":
expression.set("this", "SYSTEM_TIME")
return super().version_sql(expression)
def contains_sql(self, expression: exp.Contains) -> str:
this = expression.this
expr = expression.expression
if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower):
this = this.this
expr = expr.this
return self.func("CONTAINS_SUBSTRING", this, expr)

View file

@ -275,6 +275,7 @@ class ClickHouse(Dialect):
"EDITDISTANCE": exp.Levenshtein.from_arg_list,
"LEVENSHTEINDISTANCE": exp.Levenshtein.from_arg_list,
}
FUNCTIONS.pop("TRANSFORM")
AGG_FUNCTIONS = {
"count",

View file

@ -1724,3 +1724,14 @@ def explode_to_unnest_sql(self: Generator, expression: exp.Lateral) -> str:
def timestampdiff_sql(self: Generator, expression: exp.DatetimeDiff | exp.TimestampDiff) -> str:
return self.func("TIMESTAMPDIFF", expression.unit, expression.expression, expression.this)
def no_make_interval_sql(self: Generator, expression: exp.MakeInterval, sep: str = ", ") -> str:
args = []
for unit, value in expression.args.items():
if isinstance(value, exp.Kwarg):
value = value.expression
args.append(f"{value} {unit}")
return f"INTERVAL '{self.format_args(*args, sep=sep)}'"

View file

@ -35,6 +35,7 @@ from sqlglot.dialects.dialect import (
sha256_sql,
build_regexp_extract,
explode_to_unnest_sql,
no_make_interval_sql,
)
from sqlglot.generator import unsupported_args
from sqlglot.helper import seq_get
@ -315,6 +316,7 @@ class DuckDB(Dialect):
"BPCHAR": TokenType.TEXT,
"CHAR": TokenType.TEXT,
"CHARACTER VARYING": TokenType.TEXT,
"DETACH": TokenType.COMMAND,
"EXCLUDE": TokenType.EXCEPT,
"LOGICAL": TokenType.BOOLEAN,
"ONLY": TokenType.ONLY,
@ -558,6 +560,7 @@ class DuckDB(Dialect):
exp.Lateral: explode_to_unnest_sql,
exp.LogicalOr: rename_func("BOOL_OR"),
exp.LogicalAnd: rename_func("BOOL_AND"),
exp.MakeInterval: lambda self, e: no_make_interval_sql(self, e, sep=" "),
exp.MD5Digest: lambda self, e: self.func("UNHEX", self.func("MD5", e.this)),
exp.MonthsBetween: lambda self, e: self.func(
"DATEDIFF",
@ -645,6 +648,7 @@ class DuckDB(Dialect):
exp.DataType.Type.BINARY: "BLOB",
exp.DataType.Type.BPCHAR: "TEXT",
exp.DataType.Type.CHAR: "TEXT",
exp.DataType.Type.DATETIME: "TIMESTAMP",
exp.DataType.Type.FLOAT: "REAL",
exp.DataType.Type.NCHAR: "TEXT",
exp.DataType.Type.NVARCHAR: "TEXT",

View file

@ -25,6 +25,7 @@ from sqlglot.dialects.dialect import (
no_safe_divide_sql,
no_timestamp_sql,
timestampdiff_sql,
no_make_interval_sql,
)
from sqlglot.generator import unsupported_args
from sqlglot.helper import flatten, is_float, is_int, seq_get
@ -105,11 +106,14 @@ def _build_date_time_add(expr_type: t.Type[E]) -> t.Callable[[t.List], E]:
# https://docs.snowflake.com/en/sql-reference/functions/div0
def _build_if_from_div0(args: t.List) -> exp.If:
cond = exp.EQ(this=seq_get(args, 1), expression=exp.Literal.number(0)).and_(
exp.Is(this=seq_get(args, 0), expression=exp.null()).not_()
lhs = exp._wrap(seq_get(args, 0), exp.Binary)
rhs = exp._wrap(seq_get(args, 1), exp.Binary)
cond = exp.EQ(this=rhs, expression=exp.Literal.number(0)).and_(
exp.Is(this=lhs, expression=exp.null()).not_()
)
true = exp.Literal.number(0)
false = exp.Div(this=seq_get(args, 0), expression=seq_get(args, 1))
false = exp.Div(this=lhs, expression=rhs)
return exp.If(this=cond, true=true, false=false)
@ -866,6 +870,7 @@ class Snowflake(Dialect):
exp.LogicalAnd: rename_func("BOOLAND_AGG"),
exp.LogicalOr: rename_func("BOOLOR_AGG"),
exp.Map: lambda self, e: var_map_sql(self, e, "OBJECT_CONSTRUCT"),
exp.MakeInterval: no_make_interval_sql,
exp.Max: max_or_greatest,
exp.Min: min_or_least,
exp.ParseJSON: lambda self, e: self.func(
@ -908,9 +913,6 @@ class Snowflake(Dialect):
),
exp.TimestampTrunc: timestamptrunc_sql(),
exp.TimeStrToTime: timestrtotime_sql,
exp.TimeToStr: lambda self, e: self.func(
"TO_CHAR", exp.cast(e.this, exp.DataType.Type.TIMESTAMP), self.format_time(e)
),
exp.TimeToUnix: lambda self, e: f"EXTRACT(epoch_second FROM {self.sql(e, 'this')})",
exp.ToArray: rename_func("TO_ARRAY"),
exp.ToChar: lambda self, e: self.function_fallback_sql(e),
@ -1147,3 +1149,10 @@ class Snowflake(Dialect):
exp.ParseJSON(this=this) if this.is_string else this,
expression.expression,
)
def timetostr_sql(self, expression: exp.TimeToStr) -> str:
this = expression.this
if not isinstance(this, exp.TsOrDsToTimestamp):
this = exp.cast(this, exp.DataType.Type.TIMESTAMP)
return self.func("TO_CHAR", this, self.format_time(expression))

View file

@ -112,6 +112,161 @@ class StarRocks(MySQL):
TRANSFORMS.pop(exp.DateTrunc)
# https://docs.starrocks.io/docs/sql-reference/sql-statements/keywords/#reserved-keywords
RESERVED_KEYWORDS = {
"add",
"all",
"alter",
"analyze",
"and",
"array",
"as",
"asc",
"between",
"bigint",
"bitmap",
"both",
"by",
"case",
"char",
"character",
"check",
"collate",
"column",
"compaction",
"convert",
"create",
"cross",
"cube",
"current_date",
"current_role",
"current_time",
"current_timestamp",
"current_user",
"database",
"databases",
"decimal",
"decimalv2",
"decimal32",
"decimal64",
"decimal128",
"default",
"deferred",
"delete",
"dense_rank",
"desc",
"describe",
"distinct",
"double",
"drop",
"dual",
"else",
"except",
"exists",
"explain",
"false",
"first_value",
"float",
"for",
"force",
"from",
"full",
"function",
"grant",
"group",
"grouping",
"grouping_id",
"groups",
"having",
"hll",
"host",
"if",
"ignore",
"immediate",
"in",
"index",
"infile",
"inner",
"insert",
"int",
"integer",
"intersect",
"into",
"is",
"join",
"json",
"key",
"keys",
"kill",
"lag",
"largeint",
"last_value",
"lateral",
"lead",
"left",
"like",
"limit",
"load",
"localtime",
"localtimestamp",
"maxvalue",
"minus",
"mod",
"not",
"ntile",
"null",
"on",
"or",
"order",
"outer",
"outfile",
"over",
"partition",
"percentile",
"primary",
"procedure",
"qualify",
"range",
"rank",
"read",
"regexp",
"release",
"rename",
"replace",
"revoke",
"right",
"rlike",
"row",
"row_number",
"rows",
"schema",
"schemas",
"select",
"set",
"set_var",
"show",
"smallint",
"system",
"table",
"terminated",
"text",
"then",
"tinyint",
"to",
"true",
"union",
"unique",
"unsigned",
"update",
"use",
"using",
"values",
"varchar",
"when",
"where",
"with",
}
def create_sql(self, expression: exp.Create) -> str:
# Starrocks' primary key is defined outside of the schema, so we need to move it there
schema = expression.this

View file

@ -301,7 +301,7 @@ class Expression(metaclass=_Expression):
"""
return deepcopy(self)
def add_comments(self, comments: t.Optional[t.List[str]] = None) -> None:
def add_comments(self, comments: t.Optional[t.List[str]] = None, prepend: bool = False) -> None:
if self.comments is None:
self.comments = []
@ -313,7 +313,12 @@ class Expression(metaclass=_Expression):
k, *v = kv.split("=")
value = v[0].strip() if v else True
self.meta[k.strip()] = value
self.comments.append(comment)
if not prepend:
self.comments.append(comment)
if prepend:
self.comments = comments + self.comments
def pop_comments(self) -> t.List[str]:
comments = self.comments or []
@ -5455,6 +5460,10 @@ class ConcatWs(Concat):
_sql_names = ["CONCAT_WS"]
class Contains(Func):
arg_types = {"this": True, "expression": True}
# https://docs.oracle.com/cd/B13789_01/server.101/b10759/operators004.htm#i1035022
class ConnectByRoot(Func):
pass
@ -5584,6 +5593,17 @@ class MonthsBetween(Func):
arg_types = {"this": True, "expression": True, "roundoff": False}
class MakeInterval(Func):
arg_types = {
"year": False,
"month": False,
"day": False,
"hour": False,
"minute": False,
"second": False,
}
class LastDay(Func, TimeUnit):
_sql_names = ["LAST_DAY", "LAST_DAY_OF_MONTH"]
arg_types = {"this": True, "unit": False}
@ -5812,6 +5832,11 @@ class IsNan(Func):
_sql_names = ["IS_NAN", "ISNAN"]
# https://cloud.google.com/bigquery/docs/reference/standard-sql/json_functions#int64_for_json
class Int64(Func):
pass
class IsInf(Func):
_sql_names = ["IS_INF", "ISINF"]
@ -6304,7 +6329,7 @@ class Round(Func):
class RowNumber(Func):
arg_types: t.Dict[str, t.Any] = {}
arg_types = {"this": False}
class SafeDivide(Func):
@ -6490,6 +6515,10 @@ class TsOrDsToDate(Func):
arg_types = {"this": True, "format": False, "safe": False}
class TsOrDsToDatetime(Func):
pass
class TsOrDsToTime(Func):
pass
@ -6947,7 +6976,15 @@ def _combine(
return this
def _wrap(expression: E, kind: t.Type[Expression]) -> E | Paren:
@t.overload
def _wrap(expression: None, kind: t.Type[Expression]) -> None: ...
@t.overload
def _wrap(expression: E, kind: t.Type[Expression]) -> E | Paren: ...
def _wrap(expression: t.Optional[E], kind: t.Type[Expression]) -> t.Optional[E] | Paren:
return Paren(this=expression) if isinstance(expression, kind) else expression
@ -7793,8 +7830,8 @@ def cast(
existing_cast_type: DataType.Type = expr.to.this
new_cast_type: DataType.Type = data_type.this
types_are_equivalent = type_mapping.get(
existing_cast_type, existing_cast_type
) == type_mapping.get(new_cast_type, new_cast_type)
existing_cast_type, existing_cast_type.value
) == type_mapping.get(new_cast_type, new_cast_type.value)
if expr.is_type(data_type) or types_are_equivalent:
return expr

View file

@ -148,6 +148,7 @@ class Generator(metaclass=_Generator):
exp.InputModelProperty: lambda self, e: f"INPUT{self.sql(e, 'this')}",
exp.Intersect: lambda self, e: self.set_operations(e),
exp.IntervalSpan: lambda self, e: f"{self.sql(e, 'this')} TO {self.sql(e, 'expression')}",
exp.Int64: lambda self, e: self.sql(exp.cast(e.this, exp.DataType.Type.BIGINT)),
exp.LanguageProperty: lambda self, e: self.naked_property(e),
exp.LocationProperty: lambda self, e: self.naked_property(e),
exp.LogProperty: lambda _, e: f"{'NO ' if e.args.get('no') else ''}LOG",
@ -593,6 +594,7 @@ class Generator(metaclass=_Generator):
WITH_SEPARATED_COMMENTS: t.Tuple[t.Type[exp.Expression], ...] = (
exp.Command,
exp.Create,
exp.Describe,
exp.Delete,
exp.Drop,
exp.From,
@ -3896,7 +3898,14 @@ class Generator(metaclass=_Generator):
if isinstance(this, exp.TsOrDsToTimestamp) or this.is_type(exp.DataType.Type.TIMESTAMP):
return self.sql(this)
return self.sql(exp.cast(this, exp.DataType.Type.TIMESTAMP))
return self.sql(exp.cast(this, exp.DataType.Type.TIMESTAMP, dialect=self.dialect))
def tsordstodatetime_sql(self, expression: exp.TsOrDsToDatetime) -> str:
this = expression.this
if isinstance(this, exp.TsOrDsToDatetime) or this.is_type(exp.DataType.Type.DATETIME):
return self.sql(this)
return self.sql(exp.cast(this, exp.DataType.Type.DATETIME, dialect=self.dialect))
def tsordstodate_sql(self, expression: exp.TsOrDsToDate) -> str:
this = expression.this

View file

@ -806,7 +806,7 @@ class Parser(metaclass=_Parser):
kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
this=self._parse_table(schema=False),
),
TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
TokenType.SEMICOLON: lambda self: exp.Semicolon(),
}
UNARY_PARSERS = {
@ -1715,7 +1715,10 @@ class Parser(metaclass=_Parser):
return None
if self._match_set(self.STATEMENT_PARSERS):
return self.STATEMENT_PARSERS[self._prev.token_type](self)
comments = self._prev_comments
stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
stmt.add_comments(comments, prepend=True)
return stmt
if self._match_set(self.dialect.tokenizer.COMMANDS):
return self._parse_command()
@ -1735,9 +1738,13 @@ class Parser(metaclass=_Parser):
concurrently = self._match_text_seq("CONCURRENTLY")
if_exists = exists or self._parse_exists()
table = self._parse_table_parts(
schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
)
if kind == "COLUMN":
this = self._parse_column()
else:
this = self._parse_table_parts(
schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
)
cluster = self._parse_on_property() if self._match(TokenType.ON) else None
@ -1748,9 +1755,8 @@ class Parser(metaclass=_Parser):
return self.expression(
exp.Drop,
comments=start.comments,
exists=if_exists,
this=table,
this=this,
expressions=expressions,
kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
temporary=temporary,
@ -1772,7 +1778,6 @@ class Parser(metaclass=_Parser):
def _parse_create(self) -> exp.Create | exp.Command:
# Note: this can't be None because we've matched a statement parser
start = self._prev
comments = self._prev_comments
replace = (
start.token_type == TokenType.REPLACE
@ -1919,7 +1924,6 @@ class Parser(metaclass=_Parser):
create_kind_text = create_token.text.upper()
return self.expression(
exp.Create,
comments=comments,
this=this,
kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
replace=replace,
@ -2659,7 +2663,7 @@ class Parser(metaclass=_Parser):
)
def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
comments = ensure_list(self._prev_comments)
comments = []
hint = self._parse_hint()
overwrite = self._match(TokenType.OVERWRITE)
ignore = self._match(TokenType.IGNORE)
@ -2845,7 +2849,6 @@ class Parser(metaclass=_Parser):
# This handles MySQL's "Multiple-Table Syntax"
# https://dev.mysql.com/doc/refman/8.0/en/delete.html
tables = None
comments = self._prev_comments
if not self._match(TokenType.FROM, advance=False):
tables = self._parse_csv(self._parse_table) or None
@ -2853,7 +2856,6 @@ class Parser(metaclass=_Parser):
return self.expression(
exp.Delete,
comments=comments,
tables=tables,
this=self._match(TokenType.FROM) and self._parse_table(joins=True),
using=self._match(TokenType.USING) and self._parse_table(joins=True),
@ -2864,13 +2866,11 @@ class Parser(metaclass=_Parser):
)
def _parse_update(self) -> exp.Update:
comments = self._prev_comments
this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
returning = self._parse_returning()
return self.expression(
exp.Update,
comments=comments,
**{ # type: ignore
"this": this,
"expressions": expressions,

View file

@ -179,27 +179,42 @@ def eliminate_distinct_on(expression: exp.Expression) -> exp.Expression:
if (
isinstance(expression, exp.Select)
and expression.args.get("distinct")
and expression.args["distinct"].args.get("on")
and isinstance(expression.args["distinct"].args["on"], exp.Tuple)
and isinstance(expression.args["distinct"].args.get("on"), exp.Tuple)
):
distinct_cols = expression.args["distinct"].pop().args["on"].expressions
outer_selects = expression.selects
row_number = find_new_name(expression.named_selects, "_row_number")
window = exp.Window(this=exp.RowNumber(), partition_by=distinct_cols)
order = expression.args.get("order")
row_number_window_alias = find_new_name(expression.named_selects, "_row_number")
distinct_cols = expression.args["distinct"].pop().args["on"].expressions
window = exp.Window(this=exp.RowNumber(), partition_by=distinct_cols)
order = expression.args.get("order")
if order:
window.set("order", order.pop())
else:
window.set("order", exp.Order(expressions=[c.copy() for c in distinct_cols]))
window = exp.alias_(window, row_number)
window = exp.alias_(window, row_number_window_alias)
expression.select(window, copy=False)
# We add aliases to the projections so that we can safely reference them in the outer query
new_selects = []
taken_names = {row_number_window_alias}
for select in expression.selects[:-1]:
if select.is_star:
new_selects = [exp.Star()]
break
if not isinstance(select, exp.Alias):
alias = find_new_name(taken_names, select.output_name or "_col")
quoted = select.this.args.get("quoted") if isinstance(select, exp.Column) else None
select = select.replace(exp.alias_(select, alias, quoted=quoted))
taken_names.add(select.output_name)
new_selects.append(select.args["alias"])
return (
exp.select(*outer_selects, copy=False)
exp.select(*new_selects, copy=False)
.from_(expression.subquery("_t", copy=False), copy=False)
.where(exp.column(row_number).eq(1), copy=False)
.where(exp.column(row_number_window_alias).eq(1), copy=False)
)
return expression

163
sqlglotrs/Cargo.lock generated
View file

@ -8,12 +8,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -22,9 +16,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "heck"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indoc"
@ -38,16 +32,6 @@ version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "memoffset"
version = "0.9.0"
@ -64,48 +48,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "parking_lot"
version = "0.12.1"
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "proc-macro2"
version = "1.0.70"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.20.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b"
checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset",
"parking_lot",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
@ -114,9 +82,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.20.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5"
checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38"
dependencies = [
"once_cell",
"target-lexicon",
@ -124,9 +92,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.20.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b"
checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636"
dependencies = [
"libc",
"pyo3-build-config",
@ -134,9 +102,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.20.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b"
checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@ -146,58 +114,38 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
version = "0.20.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424"
checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "sqlglotrs"
version = "0.2.13"
version = "0.2.14"
dependencies = [
"pyo3",
]
[[package]]
name = "syn"
version = "2.0.41"
version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
@ -206,9 +154,9 @@ dependencies = [
[[package]]
name = "target-lexicon"
version = "0.12.12"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "unicode-ident"
@ -221,60 +169,3 @@ name = "unindent"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -1,6 +1,6 @@
[package]
name = "sqlglotrs"
version = "0.2.13"
version = "0.2.14"
edition = "2021"
license = "MIT"
@ -9,4 +9,4 @@ name = "sqlglotrs"
crate-type = ["cdylib"]
[dependencies]
pyo3 = "0.20.0"
pyo3 = "0.22.6"

View file

@ -43,19 +43,19 @@ impl Token {
) -> Token {
Python::with_gil(|py| Token {
token_type,
token_type_py: PyNone::get(py).into(),
text: PyString::new(py, &text).into(),
token_type_py: PyNone::get_bound(py).into_py(py),
text: PyString::new_bound(py, &text).into_py(py),
line,
col,
start,
end,
comments: PyList::new(py, &comments).into(),
comments: PyList::new_bound(py, &comments).into(),
})
}
pub fn append_comments(&self, comments: &mut Vec<String>) {
Python::with_gil(|py| {
let pylist = self.comments.as_ref(py);
let pylist = self.comments.bind(py);
for comment in comments.iter() {
if let Err(_) = pylist.append(comment) {
panic!("Failed to append comments to the Python list");
@ -74,20 +74,20 @@ impl Token {
Python::with_gil(|py| {
Ok(format!(
"<Token token_type: {}, text: {}, line: {}, col: {}, start: {}, end: {}, comments: {}>",
self.token_type_py.as_ref(py).repr()?,
self.text.as_ref(py).repr()?,
self.token_type_py.bind(py).repr()?,
self.text.bind(py).repr()?,
self.line,
self.col,
self.start,
self.end,
self.comments.as_ref(py).repr()?,
self.comments.bind(py).repr()?,
))
})
}
}
#[pymodule]
fn sqlglotrs(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
fn sqlglotrs(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Token>()?;
m.add_class::<TokenTypeSettings>()?;
m.add_class::<TokenizerSettings>()?;

View file

@ -557,27 +557,6 @@ LANGUAGE js AS
"tsql": "SELECT CAST('2008-12-25 15:30:00' AS TIME)",
},
)
self.validate_all(
"SELECT FORMAT_DATE('%Y%m%d', '2023-12-25')",
write={
"bigquery": "SELECT FORMAT_DATE('%Y%m%d', '2023-12-25')",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25' AS DATE), '%Y%m%d')",
},
)
self.validate_all(
"SELECT FORMAT_DATETIME('%Y%m%d %H:%M:%S', DATETIME '2023-12-25 15:30:00')",
write={
"bigquery": "SELECT FORMAT_DATETIME('%Y%m%d %H:%M:%S', CAST('2023-12-25 15:30:00' AS DATETIME))",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25 15:30:00' AS TIMESTAMP), '%Y%m%d %H:%M:%S')",
},
)
self.validate_all(
"SELECT FORMAT_DATETIME('%x', '2023-12-25 15:30:00')",
write={
"bigquery": "SELECT FORMAT_DATETIME('%x', '2023-12-25 15:30:00')",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25 15:30:00' AS TIMESTAMP), '%x')",
},
)
self.validate_all(
"SELECT COUNTIF(x)",
read={
@ -685,7 +664,7 @@ LANGUAGE js AS
write={
"bigquery": "SELECT DATETIME_ADD('2023-01-01T00:00:00', INTERVAL '1' MILLISECOND)",
"databricks": "SELECT TIMESTAMPADD(MILLISECOND, '1', '2023-01-01T00:00:00')",
"duckdb": "SELECT CAST('2023-01-01T00:00:00' AS DATETIME) + INTERVAL '1' MILLISECOND",
"duckdb": "SELECT CAST('2023-01-01T00:00:00' AS TIMESTAMP) + INTERVAL '1' MILLISECOND",
"snowflake": "SELECT TIMESTAMPADD(MILLISECOND, '1', '2023-01-01T00:00:00')",
},
),
@ -696,7 +675,7 @@ LANGUAGE js AS
write={
"bigquery": "SELECT DATETIME_SUB('2023-01-01T00:00:00', INTERVAL '1' MILLISECOND)",
"databricks": "SELECT TIMESTAMPADD(MILLISECOND, '1' * -1, '2023-01-01T00:00:00')",
"duckdb": "SELECT CAST('2023-01-01T00:00:00' AS DATETIME) - INTERVAL '1' MILLISECOND",
"duckdb": "SELECT CAST('2023-01-01T00:00:00' AS TIMESTAMP) - INTERVAL '1' MILLISECOND",
},
),
)
@ -706,7 +685,7 @@ LANGUAGE js AS
write={
"bigquery": "SELECT DATETIME_TRUNC('2023-01-01T01:01:01', HOUR)",
"databricks": "SELECT DATE_TRUNC('HOUR', '2023-01-01T01:01:01')",
"duckdb": "SELECT DATE_TRUNC('HOUR', CAST('2023-01-01T01:01:01' AS DATETIME))",
"duckdb": "SELECT DATE_TRUNC('HOUR', CAST('2023-01-01T01:01:01' AS TIMESTAMP))",
},
),
)
@ -1611,6 +1590,55 @@ WHERE
"snowflake": """SELECT TRANSFORM(GET_PATH(PARSE_JSON('{"arr": [1, "a"]}'), 'arr'), x -> CAST(x AS VARCHAR))""",
},
)
self.validate_all(
"SELECT STRPOS('foo@example.com', '@')",
write={
"bigquery": "SELECT STRPOS('foo@example.com', '@')",
"duckdb": "SELECT STRPOS('foo@example.com', '@')",
"snowflake": "SELECT POSITION('@', 'foo@example.com')",
},
)
self.validate_all(
"SELECT ts + MAKE_INTERVAL(1, 2, minute => 5, day => 3)",
write={
"bigquery": "SELECT ts + MAKE_INTERVAL(1, 2, day => 3, minute => 5)",
"duckdb": "SELECT ts + INTERVAL '1 year 2 month 5 minute 3 day'",
"snowflake": "SELECT ts + INTERVAL '1 year, 2 month, 5 minute, 3 day'",
},
)
self.validate_all(
"""SELECT INT64(JSON_QUERY(JSON '{"key": 2000}', '$.key'))""",
write={
"bigquery": """SELECT INT64(JSON_QUERY(PARSE_JSON('{"key": 2000}'), '$.key'))""",
"duckdb": """SELECT CAST(JSON('{"key": 2000}') -> '$.key' AS BIGINT)""",
"snowflake": """SELECT CAST(GET_PATH(PARSE_JSON('{"key": 2000}'), 'key') AS BIGINT)""",
},
)
self.validate_identity(
"CONTAINS_SUBSTRING(a, b, json_scope => 'JSON_KEYS_AND_VALUES')"
).assert_is(exp.Anonymous)
self.validate_all(
"""CONTAINS_SUBSTRING(a, b)""",
read={
"": "CONTAINS(a, b)",
"spark": "CONTAINS(a, b)",
"databricks": "CONTAINS(a, b)",
"snowflake": "CONTAINS(a, b)",
"duckdb": "CONTAINS(a, b)",
"oracle": "CONTAINS(a, b)",
},
write={
"": "CONTAINS(LOWER(a), LOWER(b))",
"spark": "CONTAINS(LOWER(a), LOWER(b))",
"databricks": "CONTAINS(LOWER(a), LOWER(b))",
"snowflake": "CONTAINS(LOWER(a), LOWER(b))",
"duckdb": "CONTAINS(LOWER(a), LOWER(b))",
"oracle": "CONTAINS(LOWER(a), LOWER(b))",
"bigquery": "CONTAINS_SUBSTRING(a, b)",
},
)
def test_errors(self):
with self.assertRaises(TokenError):
@ -2213,3 +2241,34 @@ OPTIONS (
"databricks": "REGEXP_EXTRACT_ALL('a1_a2a3_a4A5a6', '(a)[0-9]')",
},
)
def test_format_temporal(self):
self.validate_all(
"SELECT FORMAT_DATE('%Y%m%d', '2023-12-25')",
write={
"bigquery": "SELECT FORMAT_DATE('%Y%m%d', '2023-12-25')",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25' AS DATE), '%Y%m%d')",
},
)
self.validate_all(
"SELECT FORMAT_DATETIME('%Y%m%d %H:%M:%S', DATETIME '2023-12-25 15:30:00')",
write={
"bigquery": "SELECT FORMAT_DATETIME('%Y%m%d %H:%M:%S', CAST('2023-12-25 15:30:00' AS DATETIME))",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25 15:30:00' AS TIMESTAMP), '%Y%m%d %H:%M:%S')",
},
)
self.validate_all(
"SELECT FORMAT_DATETIME('%x', '2023-12-25 15:30:00')",
write={
"bigquery": "SELECT FORMAT_DATETIME('%x', '2023-12-25 15:30:00')",
"duckdb": "SELECT STRFTIME(CAST('2023-12-25 15:30:00' AS TIMESTAMP), '%x')",
},
)
self.validate_all(
"""SELECT FORMAT_TIMESTAMP("%b-%d-%Y", TIMESTAMP "2050-12-25 15:30:55+00")""",
write={
"bigquery": "SELECT FORMAT_TIMESTAMP('%b-%d-%Y', CAST('2050-12-25 15:30:55+00' AS TIMESTAMP))",
"duckdb": "SELECT STRFTIME(CAST(CAST('2050-12-25 15:30:55+00' AS TIMESTAMPTZ) AS TIMESTAMP), '%b-%d-%Y')",
"snowflake": "SELECT TO_CHAR(CAST(CAST('2050-12-25 15:30:55+00' AS TIMESTAMPTZ) AS TIMESTAMP), 'mon-DD-yyyy')",
},
)

View file

@ -251,7 +251,7 @@ class TestClickhouse(Validator):
},
write={
"clickhouse": "SELECT CAST('2020-01-01' AS Nullable(DateTime)) + INTERVAL '500' MICROSECOND",
"duckdb": "SELECT CAST('2020-01-01' AS DATETIME) + INTERVAL '500' MICROSECOND",
"duckdb": "SELECT CAST('2020-01-01' AS TIMESTAMP) + INTERVAL '500' MICROSECOND",
"postgres": "SELECT CAST('2020-01-01' AS TIMESTAMP) + INTERVAL '500 MICROSECOND'",
},
)
@ -1245,3 +1245,17 @@ LIFETIME(MIN 0 MAX 0)""",
scopes = traverse_scope(parse_one(sql, dialect=self.dialect))
self.assertEqual(len(scopes), 1)
self.assertEqual(set(scopes[0].sources), {"t"})
def test_window_functions(self):
self.validate_identity(
"SELECT row_number(column1) OVER (PARTITION BY column2 ORDER BY column3) FROM table"
)
self.validate_identity(
"SELECT row_number() OVER (PARTITION BY column2 ORDER BY column3) FROM table"
)
def test_functions(self):
self.validate_identity("SELECT TRANSFORM(foo, [1, 2], ['first', 'second']) FROM table")
self.validate_identity(
"SELECT TRANSFORM(foo, [1, 2], ['first', 'second'], 'default') FROM table"
)

View file

@ -1688,6 +1688,7 @@ class TestDialect(Validator):
"duckdb": "STRPOS(haystack, needle)",
"postgres": "STRPOS(haystack, needle)",
"presto": "STRPOS(haystack, needle)",
"bigquery": "STRPOS(haystack, needle)",
"spark": "LOCATE(needle, haystack)",
"clickhouse": "position(haystack, needle)",
"snowflake": "POSITION(needle, haystack)",

View file

@ -382,6 +382,7 @@ class TestDuckDB(Validator):
self.validate_identity(
"ATTACH DATABASE ':memory:' AS new_database", check_command_warning=True
)
self.validate_identity("DETACH DATABASE new_database", check_command_warning=True)
self.validate_identity(
"SELECT {'yes': 'duck', 'maybe': 'goose', 'huh': NULL, 'no': 'heron'}"
)

View file

@ -81,6 +81,10 @@ class TestMySQL(Validator):
self.validate_identity(
"CREATE OR REPLACE VIEW my_view AS SELECT column1 AS `boo`, column2 AS `foo` FROM my_table WHERE column3 = 'some_value' UNION SELECT q.* FROM fruits_table, JSON_TABLE(Fruits, '$[*]' COLUMNS(id VARCHAR(255) PATH '$.$id', value VARCHAR(255) PATH '$.value')) AS q",
)
self.validate_identity(
"/*left*/ EXPLAIN SELECT /*hint*/ col FROM t1 /*right*/",
"/* left */ DESCRIBE /* hint */ SELECT col FROM t1 /* right */",
)
self.validate_identity(
"CREATE TABLE t (name VARCHAR)",
"CREATE TABLE t (name TEXT)",

View file

@ -228,21 +228,21 @@ class TestRedshift(Validator):
self.validate_all(
"SELECT DISTINCT ON (a) a, b FROM x ORDER BY c DESC",
write={
"bigquery": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"databricks": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"drill": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"hive": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"mysql": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY CASE WHEN c IS NULL THEN 1 ELSE 0 END DESC, c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"oracle": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) _t WHERE _row_number = 1",
"presto": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"redshift": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"snowflake": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"spark": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"sqlite": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"starrocks": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY CASE WHEN c IS NULL THEN 1 ELSE 0 END DESC, c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"tableau": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"teradata": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"trino": "SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"bigquery": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"databricks": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"drill": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"hive": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"mysql": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY CASE WHEN c IS NULL THEN 1 ELSE 0 END DESC, c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"oracle": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) _t WHERE _row_number = 1",
"presto": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"redshift": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"snowflake": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"spark": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"sqlite": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"starrocks": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY CASE WHEN c IS NULL THEN 1 ELSE 0 END DESC, c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"tableau": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"teradata": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"trino": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC NULLS FIRST) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"tsql": "SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY CASE WHEN c IS NULL THEN 1 ELSE 0 END DESC, c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
},
)

View file

@ -605,6 +605,17 @@ WHERE
"duckdb": "CASE WHEN bar = 0 AND NOT foo IS NULL THEN 0 ELSE foo / bar END",
},
)
self.validate_all(
"DIV0(a - b, c - d)",
write={
"snowflake": "IFF((c - d) = 0 AND NOT (a - b) IS NULL, 0, (a - b) / (c - d))",
"sqlite": "IIF((c - d) = 0 AND NOT (a - b) IS NULL, 0, CAST((a - b) AS REAL) / (c - d))",
"presto": "IF((c - d) = 0 AND NOT (a - b) IS NULL, 0, CAST((a - b) AS DOUBLE) / (c - d))",
"spark": "IF((c - d) = 0 AND NOT (a - b) IS NULL, 0, (a - b) / (c - d))",
"hive": "IF((c - d) = 0 AND NOT (a - b) IS NULL, 0, (a - b) / (c - d))",
"duckdb": "CASE WHEN (c - d) = 0 AND NOT (a - b) IS NULL THEN 0 ELSE (a - b) / (c - d) END",
},
)
self.validate_all(
"ZEROIFNULL(foo)",
write={

View file

@ -39,6 +39,9 @@ class TestStarrocks(Validator):
self.validate_identity(
"""SELECT CAST(PARSE_JSON(fieldvalue) -> '00000000-0000-0000-0000-00000000' AS VARCHAR) AS `code` FROM (SELECT '{"00000000-0000-0000-0000-00000000":"code01"}') AS t(fieldvalue)"""
)
self.validate_identity(
"SELECT text FROM example_table", write_sql="SELECT `text` FROM example_table"
)
def test_time(self):
self.validate_identity("TIMESTAMP('2022-01-01')")

View file

@ -882,4 +882,4 @@ GRANT SELECT ON TABLE tbl TO user
GRANT SELECT, INSERT ON FUNCTION tbl TO user
GRANT SELECT ON orders TO ROLE PUBLIC
GRANT SELECT ON nation TO alice WITH GRANT OPTION
GRANT DELETE ON SCHEMA finance TO bob
GRANT DELETE ON SCHEMA finance TO bob

View file

@ -879,3 +879,8 @@ class TestParser(unittest.TestCase):
expr = parse_one(sql)
self.assertIsInstance(expr, exp.Insert)
self.assertIsInstance(expr.expression.expressions[0].expressions[0], cls)
def test_drop_column(self):
ast = parse_one("ALTER TABLE tbl DROP COLUMN col")
self.assertEqual(len(list(ast.find_all(exp.Table))), 1)
self.assertEqual(len(list(ast.find_all(exp.Column))), 1)

View file

@ -55,17 +55,17 @@ class TestTransforms(unittest.TestCase):
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a) a, b FROM x ORDER BY c DESC",
"SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a) a, b FROM x",
"SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY a) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY a) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a, b) a, b FROM x ORDER BY c DESC",
"SELECT a, b FROM (SELECT a, b, ROW_NUMBER() OVER (PARTITION BY a, b ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
"SELECT a, b FROM (SELECT a AS a, b AS b, ROW_NUMBER() OVER (PARTITION BY a, b ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
@ -75,7 +75,37 @@ class TestTransforms(unittest.TestCase):
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (_row_number) _row_number FROM x ORDER BY c DESC",
"SELECT _row_number FROM (SELECT _row_number, ROW_NUMBER() OVER (PARTITION BY _row_number ORDER BY c DESC) AS _row_number_2 FROM x) AS _t WHERE _row_number_2 = 1",
"SELECT _row_number FROM (SELECT _row_number AS _row_number, ROW_NUMBER() OVER (PARTITION BY _row_number ORDER BY c DESC) AS _row_number_2 FROM x) AS _t WHERE _row_number_2 = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (x.a, x.b) x.a, x.b FROM x ORDER BY c DESC",
"SELECT a, b FROM (SELECT x.a AS a, x.b AS b, ROW_NUMBER() OVER (PARTITION BY x.a, x.b ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a) x.a, y.a FROM x CROSS JOIN y ORDER BY c DESC",
"SELECT a, a_2 FROM (SELECT x.a AS a, y.a AS a_2, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x CROSS JOIN y) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a) a, a + b FROM x ORDER BY c DESC",
"SELECT a, _col FROM (SELECT a AS a, a + b AS _col, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
"SELECT DISTINCT ON (a) * FROM x ORDER BY c DESC",
"SELECT * FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1",
)
self.validate(
eliminate_distinct_on,
'SELECT DISTINCT ON (a) a AS "A", b FROM x ORDER BY c DESC',
'SELECT "A", b FROM (SELECT a AS "A", b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1',
)
self.validate(
eliminate_distinct_on,
'SELECT DISTINCT ON (a) "A", b FROM x ORDER BY c DESC',
'SELECT "A", b FROM (SELECT "A" AS "A", b AS b, ROW_NUMBER() OVER (PARTITION BY a ORDER BY c DESC) AS _row_number FROM x) AS _t WHERE _row_number = 1',
)
def test_eliminate_qualify(self):