Compare commits

...

1630 commits
0.1.4 ... main

Author SHA1 Message Date
Yoav Cohen
93450cc250
Add Snowflake COPY/REVOKE CURRENT GRANTS option (#1926)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-07-07 17:13:57 +02:00
Sergey Olontsev
1a33abda63
Clickhouse: support empty parenthesized options (#1925)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-07-06 09:06:20 +02:00
Yoav Cohen
f2fba48a7a
Add support for several Snowflake grant statements (#1922) 2025-07-06 08:58:19 +02:00
Simon Vandel Sillesen
cf9e50474e
Make GenericDialect support trailing commas in projections (#1921) 2025-07-06 08:57:20 +02:00
Yoav Cohen
ed8757f2f0
Align Snowflake dialect to new test of reserved keywords (#1924)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-07-05 08:40:35 +02:00
Yoav Cohen
d2466af20a
Add support for dropping multiple columns in Snowflake (#1918) 2025-07-05 08:18:58 +02:00
Yoav Cohen
b0bcc46e22
Add support for NULL escape char in pattern match searches (#1913)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-07-04 21:04:51 +02:00
Elia Perantoni
942d747d89
Change tag and policy names to ObjectName (#1892) 2025-07-04 18:21:31 +02:00
Sergey Olontsev
239e30a97c
Support for Postgres CREATE SERVER (#1914)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-07-03 19:04:32 +02:00
feral-dot-io
9020385c02
Add span for Expr::TypedString (#1919) 2025-07-03 18:24:51 +02:00
Yoav Cohen
be2d2f14e7
Add support for MySQL MEMBER OF (#1917) 2025-07-03 18:22:17 +02:00
carl
418b94227a
Postgres: support ADD CONSTRAINT NOT VALID and VALIDATE CONSTRAINT (#1908) 2025-07-03 18:19:26 +02:00
Yoav Cohen
015caca611
Redshift alter column type no set (#1912) 2025-07-03 18:16:21 +02:00
Ryan Schneider
a3398223d7
DuckDB: Add support for multiple TRIM arguments (#1916)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-07-02 14:57:08 +02:00
Yoav Cohen
f32a41a004
Redshift utf8 idents (#1915)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-07-01 13:52:29 +02:00
Simon Vandel Sillesen
9ffc546870
Make GenericDialect support from-first syntax (#1911) 2025-07-01 13:19:40 +02:00
Simon Vandel Sillesen
abd80f9ecb
Support remaining pipe operators (#1879)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-30 17:51:55 +02:00
Dima
3bc94234df
Fix join precedence for non-snowflake queries (#1905)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-06-28 20:24:25 +02:00
Sergey Olontsev
50c605a471
Support for Map values in ClickHouse settings (#1896)
Some checks are pending
Rust / test (beta) (push) Waiting to run
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-06-28 08:13:11 +02:00
Yoav Cohen
6c38cdcadb
Snowflake: Add support for future grants (#1906)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-27 21:21:38 +02:00
Ifeanyi Ubah
5f2b5fe7be
Fix clippy lints on 1.88.0 (#1910) 2025-06-27 14:21:17 -04:00
ZacJW
95d16e3b2d
Add support for LANGUAGE clause in CREATE PROCEDURE (#1903) 2025-06-27 18:22:21 +02:00
Elia Perantoni
1bbc05cdff
Snowflake: support multiple column options in CREATE VIEW (#1891)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-06-25 16:10:01 +02:00
Elia Perantoni
b2ab0061c1
Fix impl Ord for Ident (#1893)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-25 12:21:59 +02:00
ZacJW
b9365b3853
Support procedure argmode (#1901)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-24 08:39:02 +02:00
Denys Tsomenko
44f3be38e5
fix: parse snowflake fetch clause (#1894) 2025-06-24 08:29:44 +02:00
Michael Victor Zink
5d63663bc6
Use IndexColumn in all index definitions (#1900) 2025-06-24 08:18:03 +02:00
Dima
7865de015f
Fix limit in subqueries (#1899)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-06-22 09:22:45 +02:00
Mohamed Abdeen
1d0dc7cdd8
Postgres: Add support for text search types (#1889) 2025-06-22 09:02:51 +02:00
Simon Sawert
204d3b484d
Extend exception handling (#1884)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-21 08:12:07 +02:00
hulk
185a490218
Fix parsing error when having fields after nested struct in BigQuery (#1897)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-20 16:56:26 +02:00
hulk
b1b379e570
Add support of parsing struct field's options in BigQuery (#1890)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-06-18 07:00:53 +02:00
Andrew Lamb
be30697efb
Add license header check to CI (#1888)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-17 10:46:58 -04:00
Andrew Lamb
6f423969b0
Add license header to display_utils.rs and pretty_print.rs (#1887)
Some checks are pending
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-16 18:37:18 +02:00
Artem Osipov
e406422bac
Add support for cluster by expressions (#1883)
Some checks are pending
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
Co-authored-by: osipovartem <artem@PC.localdomain>
2025-06-16 12:33:16 +02:00
Andrew Lamb
0f2208d293
Prepare for 0.57.0 release (#1885)
Some checks failed
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-06-14 06:45:34 +02:00
Simon Sawert
703ba2cf48
Support DISTINCT AS { STRUCT | VALUE } for BigQuery (#1880)
Some checks failed
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
2025-06-11 18:12:30 +02:00
Simon Sawert
c2e83d49f6
Allow IF NOT EXISTS after table name for Snowflake (#1881) 2025-06-11 18:11:07 +02:00
Jacob Wujciak-Jens
9fc9009b94
chore: Replace archived actions-rs/install action (#1876)
Some checks are pending
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-10 19:54:21 -04:00
vimko
559b7e36d9
Add support for ALTER TABLE DROP INDEX (#1865)
Some checks are pending
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run
2025-06-10 18:26:07 +02:00
Yannick Utard
40d12b98bd
Add support for CREATE SCHEMA WITH ( <properties> ) (#1877)
Some checks are pending
Rust / test (stable) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
2025-06-10 06:50:10 +02:00
Mohamed Abdeen
84c3a1b325
MySQL: [[NOT] ENFORCED] in CHECK constraint (#1870) 2025-06-07 06:48:40 +02:00
Elia Perantoni
ff29dd25b2
Fix CASE expression spans (#1874) 2025-06-06 16:06:33 +02:00
Chen Chongchen
e2b1ae36e9
feat: Hive: support SORT BY direction (#1873) 2025-06-06 09:11:44 +02:00
Mohamed Abdeen
4cf5e571d3
Postgres: Apply ONLY keyword per table in TRUNCATE stmt (#1872) 2025-06-06 09:10:03 +02:00
Mohamed Abdeen
de2cc7b502
MySQL: Support index_name in FK constraints (#1871) 2025-06-06 09:03:59 +02:00
Artem Osipov
5327f0ce13
Add ICEBERG keyword support to ALTER TABLE statement (#1869) 2025-06-04 19:49:07 +02:00
Denys Tsomenko
394a534486
Fix: GROUPING SETS accept values without parenthesis (#1867) 2025-06-02 18:04:35 +02:00
Dmitriy Mazurin
80d47eee84
Adds support for mysql's drop index (#1864)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-05-30 09:16:36 +02:00
Hendrik Makait
a8bde39efb
Add support for TABLESAMPLE pipe operator (#1860) 2025-05-30 09:14:36 +02:00
Andrew Harper
eacf00d269
Add support for parameter default values in SQL Server (#1866) 2025-05-29 11:49:28 +02:00
hulk
9159d08c5e
Keep the COLUMN keyword only if it exists when dropping the column (#1862) 2025-05-28 07:09:40 +02:00
Andrew Harper
301726541a
Add support for table valued functions for SQL Server (#1839) 2025-05-23 07:19:16 +02:00
Mohamed Abdeen
bf2b72fbe0
Mysql: Add SRID column option (#1852) 2025-05-23 07:09:05 +02:00
Luca Cappelletti
05d7ffb1d5
Handle optional datatypes properly in CREATE FUNCTION statements (#1826)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-05-21 05:49:28 +02:00
Ophir LOJKINE
3f4d5f96ee
pretty-print CREATE VIEW statements (#1855) 2025-05-21 05:44:33 +02:00
Ophir LOJKINE
a496f78803
pretty-print CREATE TABLE statements (#1854) 2025-05-20 12:34:48 -04:00
dependabot[bot]
525ed81fde
Update criterion requirement from 0.5 to 0.6 in /sqlparser_bench (#1857)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ifeanyi <ifeanyi@validio.io>
2025-05-20 06:21:41 +02:00
Ophir LOJKINE
e7bf186e44
fix new rust 1.87 cargo clippy warnings (#1856) 2025-05-19 13:09:00 +02:00
Ophir LOJKINE
ae587dcbec
pretty print improvements (#1851) 2025-05-15 16:43:16 +02:00
Denys Tsomenko
3c59950060
Add support for INCLUDE/EXCLUDE NULLS for UNPIVOT (#1849) 2025-05-15 16:40:21 +02:00
Mohamed Abdeen
c6e897dc12
Postgresql: Add REPLICA IDENTITY operation for ALTER TABLE (#1844) 2025-05-14 09:40:44 +02:00
Andrew Harper
74a95fdbd1
Add support for DENY statements (#1836) 2025-05-14 09:21:23 +02:00
Ophir LOJKINE
178a351812
Fix big performance issue in string serialization (#1848) 2025-05-13 11:36:27 -04:00
Ophir LOJKINE
6120bb59cc
implement pretty-printing with {:#} (#1847) 2025-05-13 09:25:07 -04:00
Mohamed Abdeen
052ad4a759
Fix: parsing ident starting with underscore in certain dialects (#1835) 2025-05-10 02:14:25 +02:00
Ophir LOJKINE
2182f7ea71
Add support for the MATCH and REGEXP binary operators (#1840) 2025-05-09 01:48:23 +02:00
Andrew Harper
6cd237ea43
Allow stored procedures to be defined without BEGIN/END (#1834) 2025-05-09 01:40:03 +02:00
Luca Cappelletti
ac1c339666
Added support for CREATE DOMAIN (#1830) 2025-05-04 23:21:44 +02:00
Andrew Harper
a497358c3a
Add CREATE TRIGGER support for SQL Server (#1810) 2025-05-03 16:59:13 +02:00
benrsatori
728645fb31
Add all missing table options to be handled in any order (#1747)
Co-authored-by: Tomer Shani <tomer.shani@satoricyber.com>
2025-05-02 15:16:59 +02:00
Andrew Harper
a464f8e8d7
Improve support for cursors for SQL Server (#1831)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-05-02 05:25:30 +02:00
Luca Cappelletti
483394cd1a
Added support for DROP DOMAIN (#1828) 2025-05-02 05:16:24 +02:00
Simon Vandel Sillesen
e5d2215267
Support some of pipe operators (#1759) 2025-05-02 05:13:47 +02:00
Andrew Lamb
a5b9821d1d
Update 56.0.0 Changelog with latest commits (#1832) 2025-04-29 21:55:22 +02:00
Ifeanyi Ubah
c0921dceb9
Prepare for 0.56.0 release: Version and CHANGELOG (#1822) 2025-04-29 21:32:04 +02:00
tomershaniii
2b5bdcef0b
Snowflake: Add support for CONNECT_BY_ROOT (#1780) 2025-04-29 08:44:19 +02:00
Ifeanyi Ubah
4e392f5c07
Handle missing login in changelog generate script (#1823) 2025-04-28 13:03:39 -04:00
Andrew Harper
7703fd0d31
Add DECLARE ... CURSOR FOR support for SQL Server (#1821) 2025-04-24 20:16:49 +02:00
Andrew Harper
87d190734c
Add OR ALTER support for CREATE VIEW (#1818) 2025-04-23 18:55:57 +02:00
Andrew Harper
2eb1e7bdd4
Add CREATE FUNCTION support for SQL Server (#1808) 2025-04-23 18:10:57 +02:00
Ophir LOJKINE
945f8e0534
Add support for XMLTABLE (#1817) 2025-04-23 18:03:06 +02:00
Jax Liu
3ec80e187d
enable supports_filter_during_aggregation for Generic dialect (#1815) 2025-04-19 07:14:45 -04:00
Andrew Harper
4a487290ce
Add support for PRINT statement for SQL Server (#1811) 2025-04-18 08:59:39 +02:00
Bruno Clemente
81d8909e00
Fix STRAIGHT_JOIN constraint when table alias is absent (#1812)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-04-15 19:05:20 +02:00
Adam Johnson
3ad13af563
Add support for parenthesized subquery as IN predicate (#1793) 2025-04-15 19:01:18 +02:00
bar sela
514d2ecdaf
Snowflake: support nested join without parentheses (#1799) 2025-04-15 07:57:26 +02:00
Andrew Harper
6566c47593
Add DROP TRIGGER support for SQL Server (#1813) 2025-04-15 07:50:50 +02:00
Luca Cappelletti
896c088153
Add support for INHERITS option in CREATE TABLE statement (#1806) 2025-04-12 18:03:43 +02:00
Roman Borschel
bbc80d7537
Fix tokenization of qualified identifiers with numeric prefix. (#1803)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-04-11 20:58:43 +02:00
Yoav Cohen
d090ad4ccf
Snowflake COPY INTO target columns, select items and optional alias (#1805) 2025-04-11 11:49:43 +02:00
Roman Borschel
67c3be075e
Add support for MySQL's STRAIGHT_JOIN join operator. (#1802)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-04-10 12:26:13 +02:00
Roman Borschel
cfd8951452
Allow literal backslash escapes for string literals in Redshift dialect. (#1801)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-04-10 06:59:44 +02:00
Roman Borschel
0d2976d723
Add support for MSSQL IF/ELSE statements. (#1791)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-04-06 07:09:24 +02:00
Alexander Beedie
4deed26006
Support additional DuckDB integer types such as HUGEINT, UHUGEINT, etc (#1797)
Co-authored-by: Alexander Beedie <alexander.beedie@adia.ae>
2025-04-05 20:41:39 +02:00
DilovanCelik
610096cad8
MSSQL: Add support for functionality MERGE output clause (#1790) 2025-04-05 20:37:28 +02:00
Roman Borschel
3ed4ad9c66
Allow single quotes in EXTRACT() for Redshift. (#1795)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-04-04 22:18:31 +02:00
Ifeanyi Ubah
a847e44105
Fix clippy lint on rust 1.86 (#1796) 2025-04-04 06:34:18 -04:00
Yoav Cohen
7efa686d78
Extend snowflake grant options support (#1794) 2025-04-03 19:52:23 +02:00
LFC
776b10afe6
Add GreptimeDB to the "Users" in README (#1788) 2025-04-01 19:06:19 +02:00
Roman Borschel
45420cedd6
Fix: Snowflake ALTER SESSION cannot be followed by other statements. (#1786)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-03-31 18:09:58 +02:00
Roman Borschel
25bb871175
Enable double-dot-notation for mssql. (#1787)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-03-31 17:53:56 +02:00
Roman Borschel
91327bb0c0
Add support for Databricks TIMESTAMP_NTZ. (#1781)
Co-authored-by: Roman Borschel <roman@cluvio.com>
2025-03-31 17:51:55 +02:00
John Vandenberg
95d7b86da5
Fix typos (#1785) 2025-03-31 12:47:53 +02:00
Dan Draper
be98b30eb3
Add cipherstash-proxy to list of users in README.md (#1782) 2025-03-31 12:46:59 +02:00
bar sela
62495f2f0d
Mysql: Add support for := operator (#1779) 2025-03-27 22:48:57 +01:00
tomershaniii
53aba68e2d
Support qualified column names in MATCH AGAINST clause (#1774) 2025-03-25 10:13:11 +01:00
Mohamed Abdeen
3a8a3bb7a5
SET statements: scope modifier for multiple assignments (#1772) 2025-03-22 06:38:00 +01:00
Michael Victor Zink
939fbdd4f6
Parse SUBSTR as alias for SUBSTRING (#1769) 2025-03-22 06:34:43 +01:00
Mohamed Abdeen
f487cbe004
Add GLOBAL context/modifier to SET statements (#1767) 2025-03-20 06:52:56 +01:00
Ifeanyi Ubah
e3e88290cd
Add support for RAISE statement (#1766) 2025-03-18 15:19:51 +01:00
Mohamed Abdeen
da5892802f
Add LOCK operation for ALTER TABLE (#1768) 2025-03-18 07:22:37 +01:00
Aleksei Piianin
10cf7c164e
Snowflake: Support dollar quoted comments (#1755) 2025-03-15 07:07:07 +01:00
Ifeanyi Ubah
f81aed6359
BigQuery: Add support for CREATE SCHEMA options (#1742) 2025-03-14 08:00:19 +01:00
Ifeanyi Ubah
862e887a66
Add CASE and IF statement support (#1741) 2025-03-14 07:49:25 +01:00
Ifeanyi Ubah
cf4ab7f9ab
Add support for DROP MATERIALIZED VIEW (#1743) 2025-03-13 15:51:29 -04:00
Michael Victor Zink
fb578bb419
Preserve MySQL-style LIMIT <offset>, <limit> syntax (#1765) 2025-03-12 21:24:06 +01:00
Mohamed Abdeen
85f855150f
SET with a list of comma separated assignments (#1757) 2025-03-12 21:02:39 +01:00
Ophir LOJKINE
3392623b00
add support for with clauses (CTEs) in delete statements (#1764) 2025-03-12 11:42:51 +01:00
Michael Victor Zink
1e54a34acd
Parse MySQL ALTER TABLE DROP FOREIGN KEY syntax (#1762) 2025-03-12 07:34:18 +01:00
Luca Cappelletti
6ec5223f50
Extend support for INDEX parsing (#1707)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-03-04 06:59:39 +01:00
Ophir LOJKINE
d5dbe86da9
re-add support for nested comments in mssql (#1754) 2025-03-01 07:13:33 +01:00
Michael Victor Zink
9e09b617e8
Parse SET NAMES syntax in Postgres (#1752) 2025-03-01 07:12:25 +01:00
Michael Victor Zink
a629ddf89b
Ignore escaped LIKE wildcards in MySQL (#1735) 2025-03-01 07:07:39 +01:00
Andrew Lamb
ed416548dc
Prepare for 55.0.0 release: Version and CHANGELOG (#1750)
Co-authored-by: Ophir LOJKINE <contact@ophir.dev>
2025-02-27 12:29:59 -05:00
Michael Victor Zink
c2914f82e1
Parse ALTER TABLE AUTO_INCREMENT operation for MySQL (#1748) 2025-02-27 06:40:30 +01:00
Andrew Lamb
5b3500139a
Random test cleanups use Expr::value (#1749) 2025-02-27 06:33:08 +01:00
Michael Victor Zink
3adc746b11
Parse MySQL ALTER TABLE ALGORITHM option (#1745) 2025-02-26 07:03:38 +01:00
Michael Victor Zink
de4dbc5b1d
Parse SIGNED INTEGER type in MySQL CAST (#1739) 2025-02-26 07:00:08 +01:00
Michael
648efd7057
feat: adjust create and drop trigger for mysql dialect (#1734) 2025-02-25 07:50:29 +01:00
Ophir LOJKINE
c335c8883b
Store spans for Value expressions (#1738) 2025-02-25 07:33:57 +01:00
Ifeanyi Ubah
aab12add36
BigQuery: Add support for BEGIN (#1718) 2025-02-24 08:34:36 +01:00
Ophir LOJKINE
72312ba82a
Replace parallel condition/result vectors with single CaseWhen vector in Expr::Case (#1733) 2025-02-22 07:23:36 +01:00
Yoav Cohen
7fc37a76e5
Parse casting to array using double colon operator in Redshift (#1737) 2025-02-22 07:21:45 +01:00
SiLe Zhou
1f1c0693da
Add support for ORDER BY ALL (#1724) 2025-02-22 06:52:07 +01:00
tomershaniii
8fc8082e9a
Extend Visitor trait for Value type (#1725) 2025-02-22 06:48:39 +01:00
Artem Osipov
3ace97c0ef
Implement SnowFlake ALTER SESSION (#1712) 2025-02-21 07:22:24 +01:00
Ian Alexander Joiner
28736da235
fix: make serde feature no_std (#1730)
Co-authored-by: Jay White <JayWhite2357@users.noreply.github.com>
2025-02-21 07:18:51 +01:00
benrsatori
339239d0c5
Add support for PostgreSQL/Redshift geometric operators (#1723) 2025-02-20 19:50:32 +01:00
Michael Victor Zink
97f0be6991
Treat COLLATE like any other column option (#1731) 2025-02-20 06:26:20 +01:00
Ifeanyi Ubah
b482562618
Add support for EXECUTE IMMEDIATE (#1717) 2025-02-19 18:54:14 +01:00
Ifeanyi Ubah
3e90a18f6d
Replace Method and CompositeAccess with CompoundFieldAccess (#1716) 2025-02-19 18:49:42 +01:00
Jesse Stuart
c75a992621
Add support for Postgres ALTER TYPE (#1727) 2025-02-17 20:12:59 +01:00
Michael Victor Zink
68c41a9d5a
Differentiate LEFT JOIN from LEFT OUTER JOIN (#1726) 2025-02-14 17:23:00 +01:00
wugeer
1c0e5d3554
Add supports for Hive's SELECT ... GROUP BY .. GROUPING SETS syntax (#1653)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-02-14 17:16:10 +01:00
Tyler Brinks
a5bbb5e8ac
Add support for MS Varbinary(MAX) (#1714) (#1715) 2025-02-13 05:40:35 -05:00
Emil
3e94877f03
Support group by cube/rollup etc in BigQuery (#1720) 2025-02-11 16:22:50 +01:00
Justin Joyce
322209a9f3
Enable custom dialects to support MATCH() AGAINST() (#1719) 2025-02-10 06:51:22 +01:00
Armin Ronacher
46cfcfe8f7
Implement FROM-first selects (#1713) 2025-02-09 06:10:58 +01:00
Michael Victor Zink
cad49232c1
Parse Postgres VARBIT datatype (#1703) 2025-02-08 07:24:29 +01:00
Yoav Cohen
86abbd6028
Fix incorrect parsing of JsonAccess bracket notation after cast in Snowflake (#1708) 2025-02-06 18:14:03 +01:00
DanCodedThis
0b8ba91156
Add suppport for Show Objects statement for the Snowflake parser (#1702)
Co-authored-by: Denys Tsomenko <denys.tsomenko@caspiandb.com>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-02-06 18:11:02 +01:00
Hans Ott
443f492b4b
Require space after -- to start single line comment in MySQL (#1705) 2025-02-05 20:47:17 +01:00
Yoav Cohen
751dc5afce
Parse Snowflake COPY INTO <location> (#1669) 2025-02-05 20:23:27 +01:00
wugeer
486b29ffab
Add support for CREATE/ALTER/DROP CONNECTOR syntax (#1701) 2025-02-04 18:33:12 +01:00
Yoav Cohen
ec948eaf6e
Add parsing for GRANT ROLE and GRANT DATABASE ROLE in Snowflake dialect (#1689) 2025-02-03 20:17:47 +01:00
Rémy SAISSY
257da5a82c
Add RETURNS TABLE() support for CREATE FUNCTION in Postgresql (#1687)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-02-03 08:27:37 +01:00
Yoav Cohen
906f395341
Add support for GRANT on some common Snowflake objects (#1699) 2025-02-03 08:21:17 +01:00
Yoav Cohen
c3256a80d7
Do not parse ASOF and MATCH_CONDITION as table factor aliases (#1698) 2025-02-01 13:42:38 +01:00
Paul Grau
447142c6d0
Make TypedString preserve quote style (#1679) 2025-01-31 07:04:41 +01:00
gstvg
aeaafbe6e4
Extend lambda support for ClickHouse and DuckDB dialects (#1686) 2025-01-31 06:59:16 +01:00
Ifeanyi Ubah
94b2ff7191
Make numeric literal underscore test dialect agnostic (#1685) 2025-01-30 18:05:36 -05:00
Ifeanyi Ubah
9c384a9194
Fix CREATE FUNCTION round trip for Hive dialect (#1693) 2025-01-30 17:45:31 -05:00
Rémy SAISSY
a7e984099f
Fix DDL generation in case of an empty arguments function. (#1690) 2025-01-30 07:50:30 +01:00
Michael Victor Zink
252fdbab82
Allow plain JOIN without turning it into INNER (#1692) 2025-01-30 07:15:57 +01:00
Yoav Cohen
784605c913
Fix bug when parsing a Snowflake stage with ; suffix (#1688) 2025-01-29 17:50:36 +01:00
Ifeanyi Ubah
7980c866a3
BigQuery: Fix column identifier reserved keywords list (#1678) 2025-01-29 06:03:55 -05:00
Paul Grau
269967a6ac
Support underscore separators in numbers for Clickhouse. Fixes #1659 (#1677) 2025-01-28 14:26:08 +01:00
Ifeanyi Ubah
8de3a62948
BigQuery: Add support for select expr star (#1680) 2025-01-28 11:33:07 +01:00
AvivDavid-Satori
f7b0812b01
Add support for mysql table hints (#1675) 2025-01-28 09:41:03 +01:00
Ifeanyi Ubah
fdbe864d0d
Support multiple tables in UPDATE FROM clause (#1681) 2025-01-28 08:45:14 +01:00
Yoav Cohen
74163b148e
Add support for parsing empty dictionary expressions (#1684) 2025-01-26 15:20:00 +01:00
Yoav Cohen
cbe59a2d8b
Enable GROUP BY exp for Snowflake dialect (#1683) 2025-01-26 15:15:36 +01:00
Ayman Elkfrawy
211b15e790
Enhance object name path segments (#1539) 2025-01-26 15:13:51 +01:00
Ifeanyi Ubah
fd6c98e933
BigQuery: Support trailing commas in column definitions list (#1682) 2025-01-25 10:01:33 -05:00
Hans Ott
ef072be9e1
Only support escape literals for Postgres, Redshift and generic dialect (#1674) 2025-01-24 09:02:53 +01:00
Hans Ott
4f7154288e
National strings: check if dialect supports backslash escape (#1672) 2025-01-23 17:16:53 +01:00
Denys Tsomenko
c7c0de6551
Add support for Create Iceberg Table statement for Snowflake parser (#1664) 2025-01-20 21:39:44 +01:00
Yoav Cohen
183274e274
Add support for Snowflake account privileges (#1666) 2025-01-20 20:20:41 +01:00
Andrew Lamb
e5bc3dfad8
Update rat_exclude_file.txt (#1670) 2025-01-20 20:19:14 +01:00
Andrew Lamb
17d5610f09
Update verson to 0.54.0 and update changelog (#1668) 2025-01-20 11:32:12 -05:00
Yoav Cohen
5da702fc19
Add support for Snowflake AT/BEFORE (#1667) 2025-01-19 12:08:45 +01:00
Yoav Cohen
44df6d6f92
Add support for qualified column names in JOIN ... USING (#1663) 2025-01-19 11:43:45 +01:00
Alexander Beedie
e9498d538a
Add support for IS [NOT] [form] NORMALIZED (#1655)
Co-authored-by: Alexander Beedie <alexander.beedie@adia.ae>
2025-01-17 10:59:47 +01:00
Ophir LOJKINE
3eeb9160ea
fix parsing of INSERT INTO ... SELECT ... RETURNING (#1661) 2025-01-17 08:13:12 +01:00
Yoav Cohen
b4b5576dd4
Add support for Snowflake column aliases that use SQL keywords (#1632) 2025-01-16 17:50:30 +01:00
AvivDavid-Satori
474150006f
Add support for parsing RAISERROR (#1656) 2025-01-16 10:09:53 +01:00
Martin Abelson Sahlen
9105cae261
Allow empty options for BigQuery (#1657)
Co-authored-by: Martin Abelson Sahlen <sahlen@Mac.lan>
2025-01-16 09:27:26 +01:00
bar sela
36db176657
Support trailing commas in FROM clause (#1645)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-01-14 09:38:24 -05:00
wugeer
6507484697
Support single line comments starting with '#' for Hive (#1654) 2025-01-13 17:57:11 +01:00
Hans Ott
c808c4e4fd
Correctly look for end delimiter dollar quoted string (#1650) 2025-01-12 21:34:09 +01:00
Yoav Cohen
3b4dc0f227
MsSQL SET for session params (#1646) 2025-01-11 10:51:01 +01:00
Simon Sawert
0c3b6c0974
Add support for ClickHouse FORMAT on INSERT (#1628) 2025-01-10 18:17:28 +01:00
cjw
b09514e492
feat: support INSERT INTO [TABLE] FUNCTION of Clickhouse (#1633)
Co-authored-by: Kermit <chenjiawei1@xiaohongshu.com>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-01-10 15:23:56 +01:00
Stepan Koltsov
c54ba4dc41
ALTER TABLE DROP {COLUMN|CONSTRAINT} RESTRICT (#1651) 2025-01-10 01:29:34 +01:00
Yoav Cohen
5a761dd6db
Add support for the Snowflake MINUS set operator (#1652) 2025-01-10 00:52:09 +01:00
Michael Victor Zink
4fdf5e1b30
Fix MySQL parsing of GRANT, REVOKE, and CREATE VIEW (#1538) 2025-01-10 00:31:06 +01:00
Yoav Cohen
687ce2d5f4
Add support for MS-SQL BEGIN/END TRY/CATCH (#1649) 2025-01-08 19:31:24 +01:00
Stepan Koltsov
397bceb241
Replace ReferentialAction enum in DROP statements (#1648) 2025-01-08 19:27:25 +01:00
wugeer
62bcaa1c98
Support pluralized time units (#1630) 2025-01-08 18:28:20 +01:00
Hans Ott
0cd49fb699
Start new line if \r in Postgres dialect (#1647) 2025-01-07 18:35:03 +01:00
Yoav Cohen
8cfc46277f
Add support for MySQL's INSERT INTO ... SET syntax (#1641) 2025-01-06 20:13:38 +01:00
Yoav Cohen
4c6af0ae4f
Add support for Snowflake LIST and REMOVE (#1639) 2025-01-06 16:41:09 +01:00
Yoav Cohen
17e22f0a60
Add support for the SQL OVERLAPS predicate (#1638) 2025-01-06 16:35:24 +01:00
Yoav Cohen
e23877cb2d
Add support for various Snowflake grantees (#1640) 2025-01-05 13:31:51 -05:00
Yoav Cohen
02d60cc0fc
Add support for USE SECONDARY ROLE (vs. ROLES) (#1637) 2025-01-05 13:30:06 -05:00
Hans Ott
8bc63f0e4a
Correctly tokenize nested comments (#1629) 2025-01-05 15:37:34 +01:00
wugeer
94ea20628f
Add support for MYSQL's RENAME TABLE (#1616)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2025-01-01 21:54:58 +01:00
Andrew Lamb
3bad04e9e8
Test benchmarks and Improve benchmark README.md (#1627) 2025-01-01 21:47:59 +01:00
Andrew Lamb
fe36020890
Simplify parse_keyword_apis more (#1626) 2024-12-29 14:20:17 +01:00
Andrew Lamb
3db1b4430f
Improve parsing speed by avoiding some clones in parse_identifier (#1624) 2024-12-29 14:17:52 +01:00
Andrew Lamb
539db9fb1a
Fix sqlparser_bench benchmark compilation (#1625) 2024-12-29 14:14:06 +01:00
Ramnivas Laddad
77b5bd6fa8
Improve error for an unexpected token after DROP (#1623) 2024-12-28 14:29:28 +01:00
Hans Ott
48f025f658
SQLite: Allow dollar signs in placeholder names (#1620) 2024-12-28 14:20:48 +01:00
Jax Liu
d0d4153137
Fix the parsing result for the special double number (#1621) 2024-12-28 14:16:30 +01:00
Andrew Lamb
6daa4b059c
Refactor advancing token to avoid duplication, avoid borrow checker issues (#1618)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-12-27 15:17:52 +01:00
Ramnivas Laddad
7dbf31b587
Add support for DROP EXTENSION (#1610) 2024-12-27 13:19:42 +01:00
Andrew Lamb
d89cf801dd
Improve Parser documentation (#1617) 2024-12-27 12:24:58 +01:00
Paul J. Davis
df3c5652b1
Improve parsing performance by reducing token cloning (#1587)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-12-24 17:19:35 -05:00
Yuval Shkolar
024a878ee7
Support Snowflake Update-From-Select (#1604)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-12-24 10:00:59 -05:00
Ifeanyi Ubah
14cefc47ed
Merge composite and compound expr test cases (#1615) 2024-12-22 16:40:08 -05:00
Toby Hede
27822e254b
Handle empty projection in Postgres SELECT statements (#1613) 2024-12-22 11:19:43 -05:00
Jax Liu
0647a4aa82
Consolidate MapAccess, and Subscript into CompoundExpr to handle the complex field access chain (#1551) 2024-12-22 15:28:44 +01:00
Ayman Elkfrawy
cd898cb6a4
Support arbitrary composite access expressions (#1600) 2024-12-22 15:22:16 +01:00
Dmitrii Blaginin
84e82e6e2e
Add #[recursive] (#1522)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-12-19 14:17:20 -05:00
artorias1024
c973df35d6
Support DOUBLE data types with precision for Mysql (#1611) 2024-12-19 18:11:39 +01:00
yuyang
eae5629fb8
Support optional table for ANALYZE statement (#1599) 2024-12-19 10:18:45 +01:00
Ramnivas Laddad
6523dabcf8
Allow foreign table constraint without columns (#1608) 2024-12-19 10:10:53 +01:00
Ifeanyi Ubah
fac84d81ee
Fix test compilation issue (#1609) 2024-12-18 18:04:25 -05:00
Ayman Elkfrawy
e9ab4d6b94
Fix BigQuery hyphenated ObjectName with numbers (#1598) 2024-12-18 21:12:09 +01:00
cjw
8fcdf48e5c
Support parsing EXPLAIN ESTIMATE of Clickhouse (#1605)
Co-authored-by: Kermit <chenjiawei1@xiaohongshu.com>
2024-12-17 10:03:12 -05:00
Yoav Cohen
c69839102a
Add the alter table ON COMMIT option to Snowflake (#1606) 2024-12-17 08:39:59 +01:00
Aleksei Piianin
7867ba3cf0
Redshift: Fix parsing for quoted numbered columns (#1576) 2024-12-15 10:56:11 +01:00
Yoav Cohen
316bb14135
Add support for TABLESAMPLE (#1580) 2024-12-15 10:40:25 +01:00
Martin Abelson Sahlen
7bc6ddb8fb
Add support for BigQuery ANY TYPE data type (#1602)
Co-authored-by: Martin Abelson Sahlen <sahlen@Martins-MacBook-Air.local>
Co-authored-by: Martin Abelson Sahlen <sahlen@Mac.lan>
2024-12-15 10:39:42 +01:00
Andrew Lamb
885aa93465
Add Apache license header to spans.rs (#1594) 2024-12-13 13:01:56 -05:00
Andrew Lamb
3108828621
Run cargo fmt on derive crate (#1595) 2024-12-13 07:22:30 -05:00
Andrew Lamb
5de5312406
Update version to 0.53.0 and add release notes (#1592) 2024-12-12 09:17:13 -05:00
Ifeanyi Ubah
a13f8c6b93
Add support for ODBC functions (#1585) 2024-12-11 17:31:55 -05:00
Ifeanyi Ubah
04271b0e4e
Parse INSERT with subquery when lacking column names (#1586) 2024-12-11 17:31:24 -05:00
Yuval Shkolar
00abaf2187
Support INSERT OVERWRITE INTO syntax (#1584) 2024-12-09 15:25:10 -05:00
Yoav Cohen
d0fcc06652
Snowflake ALTER TABLE clustering options (#1579) 2024-12-06 10:41:01 +01:00
Yoav Cohen
7b50ac31c3
Parse Snowflake USE ROLE and USE SECONDARY ROLES (#1578) 2024-12-05 19:17:52 +01:00
hulk
dd7ba72a0b
Add support of the ENUM8|ENUM16 for ClickHouse dialect (#1574) 2024-12-05 15:59:07 +01:00
Michael Victor Zink
c761f0babb
Fix displaying WORK or TRANSACTION after BEGIN (#1565) 2024-12-03 20:10:28 -05:00
Michael Victor Zink
6517da6b7d
Support parsing optional nulls handling for unique constraint (#1567) 2024-12-03 20:09:00 -05:00
Michael Victor Zink
6d4188de53
Support BIT column types (#1577) 2024-12-03 19:47:12 -05:00
Philip Cristiano
e16b24679a
Encapsulate CreateFunction (#1573) 2024-12-02 12:45:14 -05:00
Ayman Elkfrawy
bd750dfada
Support Databricks struct literal (#1542) 2024-12-02 10:23:48 -05:00
Andrew Lamb
4ab3ab9147
Update comments / docs for Spanned (#1549)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-30 08:08:55 -05:00
Ayman Elkfrawy
f4f112d7d6
Support snowflake double dot notation for object name (#1540) 2024-11-30 08:02:08 -05:00
Ophir LOJKINE
96f7c0277a
json_object('k' VALUE 'v') in postgres (#1547)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-30 08:01:13 -05:00
Andrew Lamb
b0007389dc
Increase version of sqlparser_derive from 0.2.2 to 0.3.0 (#1571) 2024-11-30 08:00:34 -05:00
Michael Victor Zink
48b0e4db4e
Support MySQL size variants for BLOB and TEXT columns (#1564) 2024-11-30 07:55:54 -05:00
Andrew Lamb
a134910a36
Rename TokenWithLocation to TokenWithSpan, in backwards compatible way (#1562) 2024-11-30 07:55:21 -05:00
Jax Liu
92c6e7f79b
Support relation visitor to visit the Option field (#1556) 2024-11-29 07:08:52 -05:00
Ifeanyi Ubah
6291afb2c7
Fix clippy warnings on rust 1.83 (#1570) 2024-11-29 06:37:06 -05:00
Andrew Lamb
5a510ac4d9
Fix error in benchmark queries (#1560) 2024-11-27 11:33:31 -05:00
Mark-Oliver Junge
3c8fd74804
Implement Spanned to retrieve source locations on AST nodes (#1435)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-11-26 11:22:30 -05:00
Andrew Lamb
0adec33b94
Document micro benchmarks (#1555) 2024-11-26 11:11:56 -05:00
Ophir LOJKINE
525d1780e8
support json_object('k':'v') in postgres (#1546) 2024-11-25 16:01:23 -05:00
Yoav Cohen
fd21fae297
Fallback to identifier parsing if expression parsing fails (#1513) 2024-11-25 16:01:02 -05:00
Andrew Kane
0fb2ef331e
Include license file in sqlparser_derive crate (#1543) 2024-11-24 07:06:31 -05:00
Yoav Cohen
62fa8604af
PartiQL queries in Redshift (#1534) 2024-11-23 07:14:38 -05:00
tomershaniii
10519003ed
recursive select calls are parsed with bad trailing_commas parameter (#1521) 2024-11-23 06:33:14 -05:00
Michael Victor Zink
a1150223af
Allow example CLI to read from stdin (#1536) 2024-11-22 14:06:42 -05:00
Michael Victor Zink
fad2ddd641
Parse byte/bit string literals in MySQL and Postgres (#1532) 2024-11-20 06:55:38 +01:00
wugeer
73947a5f02
Add support for PostgreSQL UNLISTEN syntax and Add support for Postgres LOAD extension expr (#1531)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-19 16:14:28 -05:00
gaoqiangz
92be237cfc
Add support for MSSQL's JSON_ARRAY/JSON_OBJECT expr (#1507)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-18 09:22:18 -05:00
Ophir LOJKINE
f961efc0c9
support column type definitions in table aliases (#1526) 2024-11-18 09:02:22 -05:00
Ophir LOJKINE
4c629e8520
support sqlite's OR clauses in update statements (#1530) 2024-11-18 07:30:53 -05:00
delamarch3
a67a4f3cbe
Support ANTI and SEMI joins without LEFT/RIGHT (#1528) 2024-11-18 07:30:20 -05:00
hulk
4a5f20e911
Fix ClickHouse document link from Russian to English (#1527) 2024-11-18 07:29:28 -05:00
wugeer
724a1d1aba
Add support for Hive's LOAD DATA expr (#1520)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-15 09:53:31 -05:00
gaoqiangz
62eaee62dc
Add support for MSSQL's XQuery methods (#1500)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-14 15:32:57 -05:00
wugeer
2bb81444bd
Add support for MYSQL's CREATE TABLE SELECT expr (#1515) 2024-11-13 12:36:13 -05:00
hulk
6d907d3adc
Add support of COMMENT ON syntax for Snowflake (#1516) 2024-11-13 08:23:33 -05:00
Yoav Cohen
76322baf2f
Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements (#1501) 2024-11-13 06:55:26 -05:00
wugeer
632ba4cf8e
Fix the parsing error in MSSQL for multiple statements that include DECLARE statements (#1497) 2024-11-13 06:54:57 -05:00
Ophir LOJKINE
3a8369aaf5
Parse true and false as identifiers in mssql (#1510) 2024-11-13 05:25:26 -05:00
gaoqiangz
90824486df
Add support for MSSQL's OPENJSON WITH clause (#1498) 2024-11-13 01:41:13 -05:00
wugeer
e857787309
hive: support for special not expression !a and raise error for a! factorial operator (#1472)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-11-13 01:36:33 -05:00
Andrew Lamb
334a5bf354
Update CHANGELOG.md for 0.52.0 release, add scripts/ instructions for ASF releases (#1479) 2024-11-07 11:26:57 -05:00
Ophir LOJKINE
d853c35391
improve support for T-SQL EXECUTE statements (#1490) 2024-11-07 10:59:14 -05:00
Andrew Lamb
543ec6c584
Move CHANGELOG content (#1503) 2024-11-06 16:50:27 -05:00
Andrew Lamb
9394ad4c0c
Add Apache License to additional files (#1502) 2024-11-06 16:48:49 -05:00
Ophir LOJKINE
fc0e13b80e
add support for FOR ORDINALITY and NESTED in JSON_TABLE (#1493) 2024-11-06 16:04:13 -05:00
Yoav Cohen
a5b0092506
Add support for TOP before ALL/DISTINCT (#1495) 2024-11-06 12:09:55 -05:00
wugeer
05821cc7db
Add support for PostgreSQL LISTEN/NOTIFY syntax (#1485) 2024-11-06 16:51:08 +01:00
Andrew Lamb
a9a9d58c38
Fix typo in Dialect::supports_eq_alias_assigment (#1478) 2024-11-06 16:47:01 +01:00
Yoav Cohen
e2197eeca9
Add support for SHOW DATABASES/SCHEMAS/TABLES/VIEWS in Hive (#1487) 2024-11-03 08:07:06 -05:00
hulk
8de3cb0074
Fix complex blocks warning when running clippy (#1488) 2024-11-01 11:20:19 -04:00
Yoav Cohen
ee90373d35
Fix build (#1483) 2024-10-29 14:36:47 -04:00
tomershaniii
8e0d26abb3
fix for maybe_parse preventing parser from erroring on recursion limit (#1464) 2024-10-21 15:41:34 -04:00
Seve Martinez
38f1e573fe
feat: adding Display implementation to DELETE and INSERT (#1427)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-10-21 14:52:17 -04:00
David Caldwell
a8432b57db
Add PostgreSQL specfic "CREATE TYPE t AS ENUM (...)" support. (#1460) 2024-10-21 14:44:38 -04:00
Yoav Cohen
45c5d69b22
MsSQL TRY_CONVERT (#1477) 2024-10-20 16:29:55 -04:00
Aleksei Piianin
3421e1e4d4
Snowflake: support for extended column options in CREATE TABLE (#1454) 2024-10-20 14:13:25 -04:00
Yoav Cohen
1dd7d26fbb
Add support for parsing MsSql alias with equals (#1467) 2024-10-20 14:12:39 -04:00
Ophir LOJKINE
7c20d4ae1f
Fix #1469 (SET ROLE regression) (#1474) 2024-10-14 13:14:40 -04:00
Hans Ott
749b061fbf
MySQL dialect: Add support for hash comments (#1466) 2024-10-11 11:15:18 -04:00
Yoav Cohen
a4fa9e08b7
Add support for quantified comparison predicates (ALL/ANY/SOME) (#1459) 2024-10-09 17:47:14 -04:00
Xuanwo
0a941b87dc
chore: Add asf.yaml (#1463)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-10-09 13:01:06 -04:00
David Caldwell
c01e054fd8
Add "DROP TYPE" support. (#1461) 2024-10-09 09:59:00 -04:00
hulk
7905fb4905
Add support of EXPLAIN QUERY PLAN syntax for SQLite dialect (#1458) 2024-10-08 12:27:07 -04:00
David Caldwell
ac956dc963
Add support for ASC and DESC in CREATE TABLE column constraints for SQLite. (#1462) 2024-10-08 12:26:32 -04:00
nucccc
8badcdc200
Add SQLite "ON CONFLICT" column option in CREATE TABLE statements (#1442)
Co-authored-by: hulk <hulk.website@gmail.com>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-10-07 16:20:55 -04:00
Aleksei Piianin
84348d483e
Snowflake: support of views column comment (#1441) 2024-10-07 16:20:23 -04:00
Maxwell Knight
8ccb87a835
added ability to parse extension to parse_comment inside postgres dialect (#1451) 2024-10-04 16:07:26 -04:00
Yoav Cohen
e849f7f143
Add support for the LIKE ANY and ILIKE ANY pattern-matching condition (#1456) 2024-10-04 16:03:38 -04:00
hulk
32a126b27c
Fix always uses CommentDef::WithoutEq while parsing the inline comment (#1453) 2024-10-04 16:03:02 -04:00
Joshua Warner
1e0460a7df
Expand handling of LIMIT 1, 2 handling to include sqlite (#1447) 2024-09-30 13:40:07 -04:00
Andrew Lamb
ce2686a169
Add a note discouraging new use of dialect_of macro (#1448) 2024-09-30 07:08:13 -04:00
hulk
51cbd5a3e6
Implements ALTER POLICY syntax for PostgreSQL (#1446)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-09-29 06:17:31 -04:00
Heran Lin
73dc8a352d
Support DROP DATABASE (#1443) 2024-09-29 06:17:19 -04:00
hulk
2af981e4e6
Implements DROP POLICY syntax for PostgreSQL (#1445) 2024-09-29 05:58:34 -04:00
Eason
08fc6d3813
make parse_expr_with_alias public (#1444)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-09-29 05:58:00 -04:00
hulk
8a534c0e27
Implements CREATE POLICY syntax for PostgreSQL (#1440) 2024-09-25 13:32:04 -04:00
Andrew Lamb
affe8b5498
Fix codestyle CI check (#1438) 2024-09-22 07:32:37 -04:00
Thomas Dagenais
2403f79f55
Some small optimizations (#1424) 2024-09-21 06:25:14 -04:00
Andrew Lamb
9934f3d931
Update to ASF header / add when missing (#1437) 2024-09-21 06:23:28 -04:00
Aleksei Piianin
fb42425d51
MS SQL Server: add support for IDENTITY column option (#1432) 2024-09-20 12:44:24 -04:00
Fischer
71318df8b9
chore: remove redundant punctuation (#1434) 2024-09-20 12:39:17 -04:00
Siyuan Huang
04a53e5753
feat: support explain options (#1426) 2024-09-19 11:28:02 -04:00
hulk
1c505ce736
Allow to use ON CLUSTER cluster_name in TRUNCATE syntax (#1428) 2024-09-19 06:56:00 -04:00
Agaev Guseyn
246838a69f
Fix parsing of negative values (#1419)
Co-authored-by: Agaev Huseyn <h.agaev@vkteam.ru>
2024-09-16 17:04:21 -04:00
Andrew Lamb
b9f6784714 chore: Release sqlparser version 0.51.0 2024-09-11 14:19:35 -04:00
Andrew Lamb
70dbb11557
CHANGELOG for 0.51.0 (#1422) 2024-09-11 14:17:03 -04:00
Simon Sawert
b9e7754886
feat: Add support for MSSQL table options (#1414) 2024-09-11 13:09:41 -04:00
Andrew Lamb
cb0c511b05
Add a test showing how negative constants are parsed (#1421) 2024-09-10 16:19:13 -04:00
Marko Milenković
8dbcbb3c27
minor: Add databricks dialect to dialect_from_str (#1416)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-09-10 15:56:26 -04:00
gstvg
8305c5d416
minor: Implement common traits for OneOrManyWithParens (#1368) 2024-09-10 15:48:42 -04:00
hulk
6ba6068944
Fix Hive table comment should be after table column definitions (#1413) 2024-09-10 15:43:35 -04:00
hulk
a7b49b5072
Add support of DROP|CLEAR|MATERIALIZE PROJECTION syntax for ClickHouse (#1417) 2024-09-10 15:26:07 -04:00
Emil Ejbyfeldt
4875dadbf5
fix: Fix stack overflow in parse_subexpr (#1410) 2024-09-06 10:17:20 -04:00
Samuel Colvin
aa714e3447
Fix INTERVAL parsing to support expressions and units via dialect (#1398) 2024-09-06 10:16:09 -04:00
Toby Hede
1bed87a8ea
Suppor postgres TRUNCATE syntax (#1406) 2024-09-05 11:13:35 -04:00
张林伟
4d52ee7280
Support create index with clause (#1389)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-09-01 07:38:20 -04:00
Samuel Colvin
d64beea4d4
cleanup parse_statement (#1407) 2024-09-01 07:23:29 -04:00
hulk
df86f259ce
Fix identifier starts with $ should be regarded as a placeholder in SQLite (#1402) 2024-09-01 07:21:59 -04:00
hulk
7b4ac7ca9f
Add support of parsing CLUSTERED BY clause for Hive (#1397) 2024-09-01 07:21:26 -04:00
Samuel Colvin
222b7d127a
allow DateTimeField::Custom with EXTRACT in Postgres (#1394) 2024-08-26 15:56:57 -04:00
Kacper Muda
7282ce22f9
feat: support different USE statement syntaxes (#1387) 2024-08-23 11:42:51 -04:00
hulk
19e694aa91
Support ADD PROJECTION syntax for ClickHouse (#1390) 2024-08-22 12:33:44 -04:00
Andrew Lamb
11a6e6ff7b chore: Release sqlparser version 0.50.0 2024-08-16 06:05:54 -04:00
Andrew Lamb
ee2e2634ed
CHANGELOG for 0.50.0 (#1383) 2024-08-16 06:05:04 -04:00
Andrew Lamb
dd78084ca0
fix: only require DESCRIBE TABLE for Snowflake and ClickHouse dialect (#1386) 2024-08-16 05:54:58 -04:00
Jay Zhan
8c4d30bb6d
Support DuckDB struct syntax and support list of struct syntax (#1372)
Signed-off-by: jayzhan211 <jayzhan211@gmail.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-08-15 09:02:42 -04:00
Samuel Colvin
fab834dca3
rename get_next_precedence_full to get_next_precedence_default (#1378) 2024-08-14 11:47:28 -04:00
Samuel Colvin
f2235305f4
Simple custom lexical precedence in PostgreSQL dialect (#1379) 2024-08-14 11:42:40 -04:00
hulk
6a11a67fcd
Add support of FREEZE|UNFREEZE PARTITION syntax for ClickHouse (#1380) 2024-08-14 11:29:27 -04:00
Seve Martinez
c2f46ae07b
adding support for scale in CEIL and FLOOR functions (#1377) 2024-08-14 09:11:40 -04:00
Luca Cappelletti
b072ce2589
Adding support for parsing CREATE TRIGGER and DROP TRIGGER statements (#1352)
Co-authored-by: hulk <hulk.website@gmail.com>
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-08-14 09:11:16 -04:00
Seve Martinez
f5b818e74b
supporting snowflake extract syntax (#1374)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-08-13 08:56:18 -04:00
hulk
ca5262c13f
Use the local GitHub Action to replace setup-rust-action (#1371) 2024-08-13 06:59:19 -04:00
Andrew Lamb
1e209d8741
Simplify arrow_cast tests (#1367) 2024-08-08 16:58:31 -04:00
hulk
68a04cd402
Update version of GitHub Actions (#1363) 2024-08-08 16:57:21 -04:00
Jesse
2d4b9b3e56
Make Parser::maybe_parse pub (#1364) 2024-08-07 14:30:01 -04:00
hulk
dfb8b81630
Add support of ATTACH/DETACH PARTITION for ClickHouse (#1362) 2024-08-07 14:02:11 -04:00
Andrew Lamb
da484c57c4
Improve comments on Dialect (#1366) 2024-08-06 08:23:07 -04:00
Samuel Colvin
a5480ae498
Support Dialect level precedence, update Postgres Dialect to match Postgres (#1360) 2024-08-06 07:49:37 -04:00
Jax Liu
8f8c96f87f
Support parsing empty map literal syntax for DuckDB and Genric (#1361) 2024-08-04 07:47:32 -04:00
Jesse
d49acc67b1
Parse SETTINGS clause for ClickHouse table-valued functions (#1358) 2024-08-01 17:28:15 -04:00
hulk
a692ba5fd1
Add support of parsing OPTIMIZE TABLE statement for ClickHouse (#1359) 2024-08-01 17:20:56 -04:00
hulk
cc13841a37
Add support of parsing ON CLUSTER in ALTER TABLE for ClickHouse (#1342) 2024-07-30 16:31:42 -04:00
hulk
f96658006f
Allow to use the GLOBAL keyword before the join operator (#1353) 2024-07-30 16:30:46 -04:00
Ophir LOJKINE
bc15f7b4ce
Support for postgres String Constants with Unicode Escapes (#1355) 2024-07-29 17:18:16 -04:00
Joey Hain
c3ba2f33c6
Snowflake: support position with normal function call syntax (#1341)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-07-29 17:17:11 -04:00
hulk
7fdb2ec5d1
Allow to use the TABLE keyword in DESC|DESCRIBE|EXPLAIN TABLE statement (#1351) 2024-07-29 17:16:29 -04:00
Ophir LOJKINE
547d82f07d
fix CI clippy 1.80 warnings (#1357) 2024-07-29 08:49:05 -04:00
Andrew Lamb
6c64d43e1b chore: Release sqlparser version 0.49.0 2024-07-23 13:11:16 -04:00
Andrew Lamb
1e82a145ad
Add CHANGELOG for 0.49.0 (#1350) 2024-07-23 12:56:55 -04:00
hulk
390d4d3554
Add support of MATERIALIZED/ALIAS/EPHERMERAL default column options for ClickHouse (#1348) 2024-07-23 12:41:07 -04:00
hulk
b27abf00e2
Allow to use () as the GROUP BY nothing (#1347) 2024-07-22 15:50:24 -04:00
Jax Liu
48ea5640a2
Support Map literal syntax for DuckDB and Generic (#1344) 2024-07-21 08:18:50 -04:00
Alexander Beedie
71dc966586
Fix quoted identifier regression edge-case with "from" in SELECT (#1346) 2024-07-21 06:02:12 -04:00
Ifeanyi Ubah
028ada8350
Support subquery expression in SET expressions (#1343) 2024-07-20 06:55:24 -04:00
Nick Presta
845a1aaddd
[ClickHouse] Add support for WITH FILL to OrderByExpr (#1330)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-07-20 06:51:12 -04:00
hulk
20f7ac59e3
Fix AS query clause should be after the create table options (#1339) 2024-07-15 13:54:44 -04:00
hulk
993216f3ac
Enable PARTITION BY feature for PostgreSQL while parsing the create table statement (#1338) 2024-07-13 05:46:26 -04:00
hulk
9108bffc9a
Add support of table function WITH ORDINALITY modifier for Postgre Parser (#1337) 2024-07-09 17:43:22 -04:00
Andrew Lamb
285f492589 chore: Release sqlparser version 0.48.0 2024-07-09 08:58:59 -04:00
Andrew Lamb
4e956a1723
Add CHANGELOG for 0.48.0 (#1334) 2024-07-09 08:58:02 -04:00
gai takano
32b8276b32
Postgres: support for OWNER TO clause (#1314)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-07-09 07:49:48 -04:00
hulk
07278952f9
Add support of FORMAT clause for ClickHouse parser (#1335) 2024-07-09 07:49:04 -04:00
Lorrens Pantelis
9f60eb1571
Support DROP PROCEDURE statement (#1324)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-07-09 07:46:49 -04:00
Andrew Lamb
bbee052890
Add stale PR github workflow (#1331) 2024-07-08 14:38:59 -04:00
Andrew Lamb
17e5c0c1b6
Fix CI error message in CI (#1333) 2024-07-08 07:37:00 -04:00
Leonardo Yvens
66b4ec8486
Fix typo in sqlparser-derive README (#1310) 2024-07-08 06:32:45 -04:00
Mohamed Abdeen
f77192d4ec
Re-enable trailing commas in DCL (#1318) 2024-07-08 06:31:33 -04:00
hulk
0884dd920d
Support PREWHERE condition for ClickHouse dialect (#1328) 2024-07-07 08:03:23 -04:00
hulk
700bd03d6f
Support SETTINGS pairs for ClickHouse dialect (#1327)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-07-07 07:17:43 -04:00
hulk
44d7a20f64
Support GROUP BY WITH MODIFIER for ClickHouse (#1323)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-06-30 07:33:43 -04:00
hulk
0b1a413e64
Fix a few typos in comment lines (#1316)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-06-30 07:06:20 -04:00
Emil Sivervik
376889ae5d
chore(docs): refine docs (#1326) 2024-06-30 07:03:08 -04:00
gstvg
f9ab8dcc27
Support for DuckDB Union datatype (#1322) 2024-06-27 07:58:11 -04:00
Alexander Beedie
f5ccef6ea9
Fix Snowflake SELECT * wildcard REPLACE ... RENAME order (#1321) 2024-06-27 07:56:21 -04:00
hulk
a685e11993
Support parametric arguments to FUNCTION for ClickHouse dialect (#1315)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-06-23 07:36:05 -04:00
Lorrens Pantelis
7a9793b72e
Allow semi-colon at the end of UNCACHE statement (#1320) 2024-06-23 07:14:57 -04:00
Bidaya0
f3d2f78fb2
Support TO in CREATE VIEW clause for Clickhouse (#1313)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-06-23 07:13:16 -04:00
Lorrens Pantelis
f16c1afed0
Improve error messages with additional colons (#1319) 2024-06-21 18:26:23 -04:00
Emil Ejbyfeldt
79af31b672
Return errors, not panic, when integers fail to parse in AUTO_INCREMENT and TOP (#1305) 2024-06-18 09:30:24 -04:00
Ophir LOJKINE
345e2098fb
add support for update statements that contain tuple assignments (#1317) 2024-06-18 09:28:39 -04:00
Alexander Beedie
0330f9def5
Support use of BY NAME quantifier across all set ops (#1309)
Co-authored-by: Alexander Beedie <alexander.beedie@adia.ae>
Co-authored-by: Joey Hain <joey@sigmacomputing.com>
2024-06-17 14:14:40 -04:00
Philip Cristiano
deac269710
CreateIndex: Move Display fmt to struct (#1307) 2024-06-17 14:10:40 -04:00
Ilson Balliego
be77ce50ca
Add support for snowflake exclusive create table options (#1233)
Co-authored-by: Ilson Roberto Balliego Junior <ilson@validio.io>
2024-06-09 17:47:21 -04:00
Aleksei Piianin
3c33ac15bd
ClickHouse: support of create table query with primary key and parametrised table engine (#1289) 2024-06-07 08:19:32 -04:00
Ophir LOJKINE
4b60866bc7
add support for custom operators in postgres (#1302)
Co-authored-by: Joey Hain <joey@sigmacomputing.com>
2024-06-07 07:12:18 -04:00
Aleksei Piianin
2fb919d8b2
ClickHouse data types (#1285) 2024-06-07 07:09:42 -04:00
Mohamed Abdeen
6d4776b482
Enhancing Trailing Comma Option (#1212) 2024-06-07 06:44:04 -04:00
Philip Cristiano
a0f511cb21
Encapsulate CreateTable, CreateIndex into specific structs (#1291) 2024-06-05 05:25:42 -04:00
Andrew Lamb
f3f5de51e5 chore: Release sqlparser version 0.47.0 2024-06-01 06:23:18 -04:00
Andrew Lamb
521a2c9e7a
Add CHANGELOG for 0.47.0 (#1295) 2024-06-01 06:22:06 -04:00
Joey Hain
afa5f08db9
Support for Postgres array slice syntax (#1290)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-05-31 17:38:35 -04:00
Joey Hain
80c03f5c6a
Support for Snowflake ASOF joins (#1288) 2024-05-31 05:45:07 -04:00
Aleksei Piianin
375742d1fa
ClickHouse: create view with fields and data types (#1292) 2024-05-30 12:24:12 -04:00
Simon Sawert
029a999645
Add support for view comments for Snowflake (#1287)
Co-authored-by: Joey Hain <joey@sigmacomputing.com>
2024-05-30 12:21:39 -04:00
Joey Hain
c2d84f5683
Support for Snowflake dynamic pivot (#1280) 2024-05-30 12:20:16 -04:00
Ifeanyi Ubah
792e389baa
Support CREATE FUNCTION for BigQuery (#1253) 2024-05-30 12:18:41 -04:00
Joey Hain
d5faf3c54b
Support expression in AT TIME ZONE and fix precedence (#1272) 2024-05-23 13:30:05 -04:00
Joey Hain
9d15f7e9a9
Support: Databricks and generic: fix for values as table name (#1278) 2024-05-20 20:15:40 -04:00
Joey Hain
54184460b5
Snowflake: support IGNORE/RESPECT NULLS inside function argument list (#1263) 2024-05-16 14:16:43 -04:00
Joey Hain
5ed13b5af3
Databricks: support SELECT * EXCEPT (#1261) 2024-05-13 05:49:00 -04:00
Dmitry Bugakov
49d178477e
Fix DoubleColon cast skipping AT TIME ZONE #1266 (#1267) 2024-05-11 15:26:57 -04:00
Ifeanyi Ubah
036a4120b4
Support triple quoted strings (#1262) 2024-05-11 06:41:04 -04:00
Jichao Sun
e3692f4681
Support array indexing for duckdb (#1265) 2024-05-09 06:50:15 -04:00
Ifeanyi Ubah
eb36bd7138
Support multiple SET variables (#1252) 2024-05-07 12:51:39 -04:00
Joey Hain
c4f3ef9600
BigQuery: support for ANY_VALUE HAVING clause (#1258) 2024-05-06 20:33:37 -04:00
Joey Hain
a12a8882e7
Idea: add const generic peek_tokens method to parser (#1255) 2024-05-06 20:33:10 -04:00
Ifeanyi Ubah
138722a7c9
Allow keyword as field names in BigQuery struct syntax (#1254) 2024-05-06 15:34:33 -04:00
Joey Hain
c36e617d61
MySQL: support for GROUP_CONCAT() (#1256) 2024-05-06 15:32:54 -04:00
Joey Hain
d9d69a2192
Databricks: support for lambda functions (#1257) 2024-05-06 13:37:48 -04:00
Andrew Lamb
a86c58b1c9 chore: Release sqlparser version 0.46.0 2024-05-03 16:09:58 -04:00
Andrew Lamb
91a34c09d7
CHANGELOG for 0.46.0 (#1250) 2024-05-03 16:08:33 -04:00
Hiranmaya Gundu
2555f713c3
fix: allow snowflake to accept values without parens (#1249) 2024-05-03 16:05:16 -04:00
Joey Hain
a14faa36bb
Consolidate representation of function calls, remove AggregateExpressionWithFilter, ArraySubquery, ListAgg and ArrayAgg (#1247)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-05-03 14:46:03 -04:00
groobyming
5ea9c01bb2
Extended dialect triat to support numeric prefixed identifiers (#1188)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-05-03 14:20:12 -04:00
Andrew Lamb
8e64b73e9d
Accept WINDOW clause after QUALIFY when parsing (#1248)
Co-authored-by: ifeanyi <ifeanyi@validio.io>
2024-05-03 14:02:09 -04:00
dependabot[bot]
71a7262e38
Update simple_logger requirement from 4.0 to 5.0 (#1246)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-01 11:51:42 -04:00
WeblWabl
5b83c73e38
feat: add DECLARE parsing for mssql (#1235) 2024-05-01 06:51:04 -04:00
Andrew Repp
4aa37a46a9
Support ?-based jsonb operators in Postgres (#1242)
Co-authored-by: Andrew Repp <arepp@cloudflare.com>
2024-05-01 06:50:45 -04:00
Duong Cong Toai
bafaa914b0
Support Struct datatype parsing for GenericDialect (#1241) 2024-04-30 17:16:23 -04:00
Ifeanyi Ubah
fb20f8ccbe
Support BigQuery window function null treatment (#1239) 2024-04-30 16:44:13 -04:00
Ifeanyi Ubah
8626051513
Extend pivot operator support (#1238) 2024-04-30 14:13:26 -04:00
Joey Hain
4bfa399919
Improve parsing of JSON accesses on Postgres and Snowflake (#1215)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
2024-04-30 10:49:05 -04:00
Ifeanyi Ubah
0606024353
Support for MSSQL CONVERT styles (#1219) 2024-04-30 10:22:13 -04:00
Ifeanyi Ubah
6fcf8c9abe
BigQuery: Support window clause using named window (#1237) 2024-04-30 09:41:24 -04:00
Joey Hain
0b5722afbf
Support for CONNECT BY (#1138) 2024-04-27 06:52:21 -04:00
Joey Hain
deaa6d8151
Snowflake: support for object constants (#1223) 2024-04-26 14:01:33 -04:00
Joey Hain
2490034948
Initial Databricks SQL dialect (#1220) 2024-04-26 14:01:09 -04:00
Ifeanyi Ubah
0adf4c675c
Support BigQuery MERGE syntax (#1217) 2024-04-26 14:00:54 -04:00
Simon Sawert
b51f2a0c25
fix: Add support for MAX for NVARCHAR (#1232) 2024-04-26 13:56:37 -04:00
Yuval Shkolar
547c5cde14
fix redundant brackets in Hive/Snowflake/Redshift (#1229) 2024-04-24 07:56:09 -04:00
universalmind303
ce85084deb
feat: add fixed size list support (#1231) 2024-04-23 17:53:03 -04:00
Joey Hain
39980e8976
Support Snowflake MATCH_RECOGNIZE syntax (#1222) 2024-04-22 16:17:50 -04:00
tison
bf89b7d808
Encapsulate Insert and Delete into specific structs (#1224)
Signed-off-by: tison <wander4096@gmail.com>
2024-04-21 09:13:18 -04:00
Ifeanyi Ubah
d2c2b15f9e
Add support for quoted string backslash escaping (#1177) 2024-04-21 09:07:56 -04:00
Kould
7b49c69b3a
Support Modify Column for MySQL dialect (#1216) 2024-04-21 08:32:53 -04:00
Hiranmaya Gundu
4604628c43
feat: implement select * ilike for snowflake (#1228) 2024-04-21 08:22:08 -04:00
Joey Hain
d1f67bdc47
Preserve double colon casts (and simplify cast representations) (#1221) 2024-04-21 08:21:58 -04:00
Hiranmaya Gundu
9db20e293f
fix: have wildcard replace work in duckdb and snowflake syntax (#1226) 2024-04-21 08:20:41 -04:00
Andrew Lamb
2f03fad339 chore: Release sqlparser version 0.45.0 2024-04-12 06:54:36 -04:00
Andrew Lamb
acc5dd9376
CHANGELOG for 0.45.0 (#1213) 2024-04-12 06:52:11 -04:00
ZacJW
e5c860213b
Fix dollar quoted string tokenizer (#1193) 2024-04-12 06:38:04 -04:00
Andrew Lamb
a0ed14ce02
Do not allocate in impl Display for DateTimeField (#1209) 2024-04-09 17:23:22 -04:00
Ifeanyi Ubah
eda86d8ed7
Add support for arbitrary map access expr (#1179) 2024-04-09 17:21:22 -04:00
Ifeanyi Ubah
127be97369
Support more DateTimeField variants (#1191) 2024-04-09 17:16:03 -04:00
Ifeanyi Ubah
8dd213cff2
BigQuery: support unquoted hyphen in table/view declaration (#1178) 2024-04-09 17:05:31 -04:00
Andrew Lamb
241da85d67
Support CREATE/DROP SECRET for duckdb dialect (#1208)
Co-authored-by: Jichao Sun <4977515+JichaoS@users.noreply.github.com>
2024-04-09 16:21:08 -04:00
Nikita-str
8f67d1a713
Support MySQL UNIQUE table constraint (#1164)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-04-09 16:20:24 -04:00
yassun7010
6da8828c1b
feat: support tailing commas on snowflake dialect. (#1205) 2024-04-09 16:19:27 -04:00
Maciej Obuchowski
17ef71e42b
Fix parse COPY INTO stage names without parens for SnowFlake (#1187)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2024-04-07 08:45:59 -04:00
xring
20c5754784
Support [FIRST | AFTER column_name] support in ALTER TABLE for MySQL (#1180) 2024-04-07 08:43:23 -04:00
Ifeanyi Ubah
732e1ec1fc
BigQuery support inline comment with hash syntax (#1192) 2024-04-07 08:31:04 -04:00
Nikita-str
23103302e6
Support named windows in OVER (window_definition) clause (#1166)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-04-07 08:20:21 -04:00
Nikita-str
83c5d8191b
solve stack overflow on RecursionLimitExceeded during debug building (#1171)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-04-07 08:12:48 -04:00
Andrew Lamb
05af4e049c
Cleanup CREATE FUNCTION tests (#1203) 2024-04-07 07:08:55 -04:00
Joey Hain
3bf40485c5
Fix parsing of equality binop in function argument (#1182) 2024-04-06 13:08:40 -04:00
sunxunle
e976a2ee43
chore: fix some comments (#1184)
Signed-off-by: sunxunle <sunxunle@gmail.com>
2024-04-06 13:06:53 -04:00
Daniel Imfeld
2bf93a470c
Support PARALLEL ... and for ..ON NULL INPUT ... to CREATE FUNCTION` (#1202) 2024-04-06 13:03:00 -04:00
gstvg
14b33ac493
Add support for DuckDB functions named arguments with assignment operator (#1195)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-04-06 12:46:36 -04:00
gstvg
e747c9c2af
Add support for DuckDB struct literal syntax (#1194)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-03-29 09:39:52 -04:00
Marko Milenković
4472789171
Add support for $$ in generic dialect ... (#1185) 2024-03-24 14:20:15 -04:00
Ophir LOJKINE
6b03a259aa
Parse SUBSTRING FROM syntax in all dialects, reflect change in the AST (#1173) 2024-03-13 11:08:27 -04:00
Michiel De Backker
929c646bba
Add identifier quote style to Dialect trait (#1170) 2024-03-11 16:27:25 -04:00
Mehmet Emin KARAKAŞ
11899fd0cb
Support row_alias and col_aliases in INSERT statement for mysql and generic dialects (#1136) 2024-03-08 15:03:49 -05:00
Andrew Lamb
5da66adda9 chore: Release sqlparser version 0.44.0 2024-03-03 02:30:34 -05:00
Andrew Lamb
1af1a6e87a
Version 0.44.0 CHANGELOG (#1161) 2024-03-03 02:29:21 -05:00
Jonathan Lehto
ef4668075b
Support EXPLAIN / DESCR / DESCRIBE [FORMATTED | EXTENDED] (#1156)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-03-01 14:07:04 -05:00
Jonathan Lehto
991dbab755
Support ALTER TABLE ... SET LOCATION (#1154)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-03-01 14:05:05 -05:00
Jonathan Lehto
6f090e5547
adding delimited (#1155) 2024-03-01 13:55:50 -05:00
Jonathan Lehto
fb7d4d40cc
Support serdeproperties for CREATE TABLE with HIVE (#1152)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-03-01 13:49:41 -05:00
Jonathan Lehto
68b52a4ad6
Support EXECUTE ... USING for Postgres (#1153) 2024-03-01 13:49:29 -05:00
Andrew Lamb
9db9d22480
Support postgres style CREATE FUNCTION in GenericDialect (#1159) 2024-03-01 13:43:29 -05:00
Jonathan Lehto
a511c47bd0
set_tblproperties (#1151) 2024-03-01 13:42:21 -05:00
Andrew Lamb
10cc54e10e
Clean up nightly clippy lints (#1158) 2024-02-29 14:56:36 -05:00
Jonathan Lehto
e2ce324722
Support Unload statement (#1150)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-02-29 14:55:46 -05:00
JasonLi
4d1eecd0fc
Handle escape, unicode, and hex in tokenize_escaped_single_quoted_string (#1146)
Co-authored-by: jasonnnli <jasonnnli@tencent.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-02-29 14:33:22 -05:00
Andrew Repp
0c5f6fbf81
ISSUE-1147: Add support for MATERIALIZED CTEs (#1148)
Co-authored-by: Andrew Repp <arepp@cloudflare.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-02-29 07:54:36 -05:00
Ifeanyi Ubah
57113a9344
Support DECLARE syntax for snowflake and bigquery (#1122) 2024-02-29 07:34:00 -05:00
Liang-Chi Hsieh
f75bb4be20
Add parse_keyword_with_tokens for paring keyword and tokens combination (#1141) 2024-02-29 07:15:51 -05:00
Lukasz Stefaniak
1cf6585649
SupportSELECT AS VALUE and SELECT AS STRUCT for BigQuery (#1135) 2024-02-29 07:14:00 -05:00
Joey Hain
6a9b6f547d
Support for (+) outer join syntax (#1145) 2024-02-28 17:27:42 -05:00
Joris Bayer
b284fdfb7e
Fix panic for REPLACE (#1140)
Co-authored-by: Joris Bayer <joris.bayer@protonmail.com>
2024-02-28 17:22:19 -05:00
Philippe Noël
92781c1c05
Add ParadeDB to list of known users (#1142) 2024-02-26 11:31:48 -05:00
Ophir LOJKINE
1a07c5d67c
accept JSON_TABLE both as an unquoted table name and a table-valued function (#1134) 2024-02-15 06:34:38 -05:00
Ophir LOJKINE
d59b6638fa
add support for insert into ... select ... returning ... (#1132) 2024-02-12 16:44:22 -05:00
universalmind303
a5ac425f46
feat: add duckdb "INSTALL" and "LOAD" (#1127)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-02-08 20:39:56 -05:00
universalmind303
d981b0996a
feat: support = operator in function args (#1128)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2024-02-08 20:24:42 -05:00
Andrew Lamb
6245231479
Fix clippy warning from rust 1.76 (#1130) 2024-02-08 20:18:35 -05:00
Andrew Lamb
4b3ae8bd4b
fix release instructions (#1115) 2024-02-04 08:59:14 -05:00
Aleksei Piianin
60baea4ae7
BigQuery: support of CREATE VIEW IF NOT EXISTS (#1118) 2024-02-04 08:59:03 -05:00
Greg Gaughan
8fae601743
Add support for UPDATE FROM for SQLite (further to #694) (#1117) 2024-02-04 08:58:51 -05:00
Ifeanyi Ubah
df738f9b10
BigQuery: Parse optional DELETE FROM statement (#1120) 2024-02-04 08:57:33 -05:00
Michael Ionov
61089f977c
feat: add mysql show status statement (#1119)
Co-authored-by: Michael Ionov <michael@appdome.com>
2024-02-04 08:52:46 -05:00
Andrew Lamb
bcecd853f7 chore: Release sqlparser version 0.43.1 2024-01-25 16:18:36 -05:00
Andrew Lamb
d8235c26c5
Fix changelog about version 0.43.0 (#1113) 2024-01-25 16:11:19 -05:00
Andrew Lamb
4599ad865a chore: Release sqlparser version 0.43.0 2024-01-25 15:45:55 -05:00
Andrew Lamb
ec42539647 chore: Release sqlparser version 0.42.0 2024-01-25 15:45:40 -05:00
Andrew Lamb
360f4d008d
Update CHANGELOG.md for 0.42.0 release (#1111) 2024-01-25 15:44:11 -05:00
Joey Hain
4be8117af0
Fix :start and :end json accesses on snowflake (#1110) 2024-01-25 14:59:33 -05:00
Quinn Sinclair
f5e27366f3
Use Option<Expr> for Min and Max vals in Seq Opts, fix alter col seq display (#1106) 2024-01-25 07:12:34 -05:00
wzzzzd
1b6b6aa65f
Replace AtomicUsize with Cell<usize> in the recursion counter (#1098) 2024-01-24 14:29:51 -05:00
Daniel Imfeld
c86508bae5
Add support for constraint characteristics clause (#1099) 2024-01-24 14:26:19 -05:00
Nicolas Grislain
1fb9f3efdf
Add Qrlew as a user in README.md (#1107) 2024-01-24 14:26:06 -05:00
Andrew Repp
70764a17e9
ISSUE-1088: Fix array_agg wildcard behavior (#1093)
Co-authored-by: Andrew Repp <arepp@cloudflare.com>
2024-01-24 07:42:39 -05:00
Joey Hain
398a81029e
Support for unquoted hyphenated identifiers on bigquery (#1109) 2024-01-23 20:04:22 -05:00
Quinn Sinclair
498708c463
Error on dangling NO in CREATE SEQUENCE options (#1104) 2024-01-23 19:59:52 -05:00
Ifeanyi Ubah
3a6d3ecba2
Add support for BigQuery table and view options (#1061) 2024-01-23 17:21:53 -05:00
Marko Grujic
c7d2903c6d
Add Postgres operators for the LIKE expression variants (#1096) 2024-01-22 14:50:29 -05:00
0rphon
d72f0a966b
Add APIs to reuse token buffers in Tokenizer (#1094) 2024-01-22 14:46:36 -05:00
Michael Ionov
b0b62887a2
Allow string values in pragma commands (#1101)
Co-authored-by: Michael Ionov <michael@appdome.com>
2024-01-18 15:22:35 -05:00
Alexander Beedie
3ec337ec5f
Add "timezone_region" and "timezone_abbr" support for EXTRACT (and DATE_PART) (#1090) 2024-01-16 08:46:10 -05:00
Alexander Beedie
5d66dc5dc9
Add support for JSONB datatype (#1089) 2024-01-15 05:46:09 -05:00
Alexander Beedie
7cb1654d81
Add support for PostgreSQL ^@ starts-with operator (#1091) 2024-01-15 05:42:03 -05:00
Boyd Johnson
a71b3f5e82
Add support for PostgreSQL Insert table aliases (#1069) (#1084) 2024-01-14 13:52:31 -05:00
Andrew Lamb
ce498864dc
Bump version of sqlparser-derive to 0.2.2 (#1083) 2024-01-03 06:56:02 -05:00
Toby Hede
0be42eed58
Adds support for pg CREATE EXTENSION (#1078) 2024-01-02 12:44:59 -05:00
Toby Hede
1d63466ef8
Support for pg ADD GENERATED in ALTER COLUMN statements (#1079)
Signed-off-by: Toby Hede <toby@cipherstash.com>
2024-01-02 10:22:25 -05:00
Thomas Kluyver
a430d1a5a7
Support SQLite column definitions with no type (#1075) 2024-01-01 12:45:25 -05:00
Toby Hede
a75778c8c7
Add support for ENABLE and DISABLE on ALTER TABLE for pg (#1077)
Signed-off-by: Toby Hede <toby@cipherstash.com>
2023-12-31 09:14:52 -05:00
Mehmet Emin KARAKAŞ
593c090b21
Support MySQL FLUSH statement (#1076) 2023-12-31 09:12:03 -05:00
Mehmet Emin KARAKAŞ
c62ecb1100
Support Mysql REPLACE statement and PRIORITY clause of INSERT (#1072) 2023-12-24 07:24:53 -05:00
Andrew Lamb
7ea47c71fb chore: Release sqlparser version 0.41.0 2023-12-22 14:17:28 -05:00
Andrew Lamb
52bb67aad3
Add Changelog for 0.41.0 (#1073) 2023-12-22 14:14:20 -05:00
Joey Hain
2950a843c3
snowflake: fix rendering of SELECT TOP (#1070) 2023-12-22 13:43:31 -05:00
Takahiro Ebato
1baec96685
Add support for DEFERRED, IMMEDIATE, and EXCLUSIVE in SQLite's BEGIN TRANSACTION command (#1067) 2023-12-20 16:00:12 -05:00
Andrew Lamb
40bc407799
Improve documentation formatting (#1068) 2023-12-19 15:55:00 -05:00
Joris Bayer
29b4ce81c1
Replace type_id() by trait method to allow wrapping dialects (#1065) 2023-12-19 15:54:48 -05:00
Thomas Kluyver
e027b3cad2
Document that comments aren't preserved for round trip (#1060) 2023-12-19 15:43:10 -05:00
Thomas Kluyver
da2296e6d6
Add support for generated columns skipping 'GENERATED ALWAYS' keywords (#1058) 2023-12-19 15:42:25 -05:00
zzzdong
d0fce121ef
feat(mysql): Increased compatibility for MySQL (#1059)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-12-19 15:38:52 -05:00
Ophir LOJKINE
f46f147ffa
add support for JSON_TABLE (#1062) 2023-12-19 15:04:09 -05:00
Ophir LOJKINE
1933f194e7
add support for CALL statements (#1063) 2023-12-19 15:01:44 -05:00
Philip Dubé
8d97330d42
Update sqlparser-derive to use syn 2.0 (#1040)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-11-27 13:16:46 -05:00
Andrew Lamb
28e0a7cedc
Update sqlparser to version 0.40.0 (#1056) 2023-11-27 12:58:41 -05:00
Andrew Lamb
b69aed96e5
Update sqlparser-derive version (#1055) 2023-11-27 12:55:54 -05:00
Andrew Lamb
a765146ad1
Prepare for 0.40.0 release, derive 0.2.0 release (#1053) 2023-11-27 12:43:29 -05:00
Andrew Lamb
64eccdbba2
Document round trip ability (#1052) 2023-11-27 12:29:59 -05:00
Joey Hain
86aa044032
add {pre,post}_visit_query to Visitor (#1044) 2023-11-27 12:11:27 -05:00
Thomas Kluyver
640b9394cd
Add support for generated virtual columns with expression (#1051) 2023-11-22 13:16:15 -05:00
Toby Hede
541d684fba
Adds support for PostgreSQL "END" (#1035)
Signed-off-by: Toby Hede <toby@cipherstash.com>
2023-11-21 15:21:35 -05:00
Drew Thomas
3d2773a794
Support INSERT INTO ... DEFAULT VALUES ... (#1036) 2023-11-21 15:21:26 -05:00
Drew Thomas
5bdf2e6608
Add support for release and rollback to savepoint syntax (#1045) 2023-11-20 19:51:48 -05:00
Ophir LOJKINE
c905ee0cb8
Support CONVERT expressions (#1048) 2023-11-20 14:55:18 -05:00
Mehmet Emin KARAKAŞ
c0c2d58910
Support global and session parts in show variables for mysql and generic dialects (#1032) 2023-11-20 14:47:55 -05:00
Lukasz Stefaniak
dc2ceedeea
snowflake: PIVOT on derived table factors (#1027) 2023-11-20 10:18:29 -05:00
Drew Thomas
5a3f19310e
Fix extra whitespace printed before ON CONFLICT (#1037) 2023-11-20 09:23:09 -05:00
Jonathan
c887c4e545
Add PRQLto list of users (#1031)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-11-18 08:27:21 -05:00
Ophir LOJKINE
953c833a4a
Support mssql json and xml extensions (#1043) 2023-11-18 07:03:12 -05:00
Ophir LOJKINE
ff8312bfd8
add support for MAX as a character length (#1038) 2023-11-10 15:57:56 -05:00
Andrew Lamb
4cdaa40abe
Support IN () syntax of SQLite, alternate proposal (#1028) 2023-10-29 07:31:08 -04:00
Andrew Lamb
2f0c99c405 chore: Release sqlparser version 0.39.0 2023-10-27 15:41:59 -04:00
Andrew Lamb
cf37c013ee
CHANGELOG for 0.39.0 release (#1029) 2023-10-27 15:40:11 -04:00
Lukasz Stefaniak
254ccfb4d8
snowflake: add support for LATERAL FLATTEN and similar (#1026) 2023-10-27 14:52:47 -04:00
Lukasz Stefaniak
8164b7c316
common: Make sure + - * / % binary operators work the same in all dialects (#1025) 2023-10-27 05:45:18 -04:00
Lukasz Stefaniak
7b3cc18229
snowflake: Fix handling of /~% in the stage name (#1009) 2023-10-26 15:23:57 -04:00
Ifeanyi Ubah
2f437db2a6
Support for BigQuery struct, array and bytes , int64, float64 datatypes (#1003) 2023-10-25 12:57:33 -04:00
yuval-illumex
65317edcb9
Support Snowflake - allow number as placeholder (e.g. :1) (#1001) 2023-10-25 12:53:09 -04:00
yuval-illumex
7993384686
Support date 'key' when using semi structured data (#1023) 2023-10-24 16:05:43 -04:00
yuval-illumex
b89edaa98b
Support IGNORE|RESPECT NULLs clause in window functions (#998)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-24 09:45:59 -04:00
Andrew Lamb
8262abcd31
Improve documentation on Parser::consume_token and friends (#994) 2023-10-24 07:35:59 -04:00
Ophir LOJKINE
c5a7d6ccb9
Support for single-quoted identifiers (#1021)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-24 07:20:12 -04:00
Chris A
004a8dc5dd
Support multiple PARTITION statements in ALTER TABLE ADD statement (#1011)
Co-authored-by: Chris A <chrisa@indeed.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-24 07:19:01 -04:00
Chris A
9832adb376
Support "with" identifiers surrounded by backticks in GenericDialect (#1010) 2023-10-24 06:33:51 -04:00
Ophir LOJKINE
57090537f0
Test that regexp can be used as an identifier in postgres (#1018) 2023-10-24 06:30:05 -04:00
Mehmet Emin KARAKAŞ
86aa1b96be
Support INSERT IGNORE in MySql and GenericDialect (#1004)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-24 05:45:25 -04:00
Andrew Lamb
6739d377bd
Add docstrings for Dialects, update README (#1016) 2023-10-23 18:09:02 -04:00
Ilya
8b2a248d7b
parse SQLite pragma statement (#969)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-23 18:07:39 -04:00
Andrew Lamb
2798b65b42
snowflake/generic: position can be the name of a column (#1022)
Co-authored-by: Lukasz Stefaniak <lustefaniak@gmail.com>
2023-10-23 18:07:00 -04:00
Ophir LOJKINE
ce62fe6d27
Support FILTER in over clause (#1007)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-23 18:06:39 -04:00
Lukasz Stefaniak
e857a45201
Support SELECT * EXCEPT/REPLACE syntax from ClickHouse (#1013) 2023-10-23 17:55:11 -04:00
Joey Hain
56f24ce236
Support subquery as function arg w/o parens in Snowflake dialect (#996) 2023-10-23 17:50:45 -04:00
Alexander Beedie
5c10668dbb
Add support for UNION DISTINCT BY NAME syntax (#997)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-10-23 17:37:31 -04:00
Ophir LOJKINE
c03586b727
Support mysql RLIKE and REGEXP binary operators (#1017) 2023-10-20 16:13:22 -04:00
Lukasz Stefaniak
88510f6625
fix column COLLATE not displayed (#1012) 2023-10-20 15:49:18 -04:00
Lukasz Stefaniak
c68e9775a2
Support bigquery CAST AS x [STRING|DATE] FORMAT syntax (#978) 2023-10-20 14:33:12 -04:00
Zdenko Nevrala
83cb734b3c
Support Snowflake/BigQuery TRIM. (#975) 2023-10-06 14:48:18 -04:00
Gabriel Villalonga Simon
5263da68cd
Handle CREATE [TEMPORARY|TEMP] VIEW [IF NOT EXISTS] (#993) 2023-10-05 15:32:43 -04:00
Andrew Lamb
02f3d78a92
Fix for clippy 1.73 (#995) 2023-10-05 15:25:03 -04:00
Lukasz Stefaniak
c811e22605
redshift: add support for CREATE VIEW … WITH NO SCHEMA BINDING (#979) 2023-10-02 13:42:01 -04:00
Joey Hain
40e2ecbdf3
snowflake: support for UNPIVOT and a fix for chained PIVOTs (#983) 2023-10-02 13:28:13 -04:00
Lukasz Stefaniak
2786c7eaf1
clickhouse: add support for LIMIT BY (#977) 2023-10-02 11:53:32 -04:00
Ifeanyi Ubah
993769ec02
Add support for mixed BigQuery table name quoting (#971)
Co-authored-by: ifeanyi <ifeanyi@validio.io>
2023-10-02 08:48:51 -04:00
Ulrich Schmidt-Goertz
6ffc3b3a52
Support DELETE with ORDER BY and LIMIT (MySQL) (#992) 2023-10-02 08:42:58 -04:00
William
ed39329060
Add JumpWire to users in README (#990) 2023-10-02 08:36:17 -04:00
Lukasz Stefaniak
4903bd4b8b
Add test for clickhouse: tokenize == as Token::DoubleEq (#981) 2023-10-02 07:39:44 -04:00
Lukasz Stefaniak
e718ce6c42
bigquery: EXTRACT support For DAYOFWEEK, DAYOFYEAR, ISOWEEK, TIME (#980) 2023-10-02 07:23:25 -04:00
Ophir LOJKINE
495d0a02d5
Add support for ATTACH DATABASE (#989) 2023-10-02 07:10:56 -04:00
Andrew Lamb
7723ea56c5 chore: Release sqlparser version 0.38.0 2023-09-21 13:47:15 -04:00
Andrew Lamb
521ffa945c
Changelog for 0.38.0 release (#973) 2023-09-21 13:45:19 -04:00
Ilya
71c35d4dfd
Add support for == operator for Sqlite (#970) 2023-09-19 21:31:11 -04:00
chunshao.rcs
f6e4be4c15
Support mysql partition to table selection (#959)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-09-14 14:21:47 -04:00
William
a16791d019
Support UNNEST as a table factor for PostgreSQL (#968) 2023-09-14 13:56:49 -04:00
artorias1024
0480ee9886
feat: Add support for parsing the syntax of MySQL UNIQUE KEY. (#962)
Co-authored-by: yukunpeng <yukunpeng@zhoupudata.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-09-08 06:58:31 -04:00
Berkay Şahin
bb7b05e106
feat: Group By All (#964)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-09-08 06:47:56 -04:00
ding-young
2593dcfb79
Add missing token loc in parse err msg (#965) 2023-09-08 06:12:44 -04:00
Forbes Lindesay
25e037c50f
feat: allow multiple actions in one ALTER TABLE statement (#960) 2023-09-07 16:39:47 -04:00
SeanTroyUWO
e0afd4b179
ANY and ALL contains their operators (#963) 2023-09-07 16:32:50 -04:00
dawg
b02c3f87ec
feat: show location info in parse errors (#958) 2023-09-07 16:23:09 -04:00
Andrew Lamb
4c3a4ad5a8
Update release documentation (#954) 2023-08-25 12:21:40 -04:00
Andrew Lamb
14da37d182
Fix Rust 1.72 clippy lints (#957) 2023-08-25 12:21:31 -04:00
David Dolphin
4a2fa66b55
[cli] add --sqlite param (#956) 2023-08-25 12:06:25 -04:00
Andrew Lamb
9c2e8bcdbc
Break test and coverage test into separate jobs (#949) 2023-08-22 08:32:14 -04:00
Andrew Lamb
b8a58bbc11 chore: Release sqlparser version 0.37.0 2023-08-22 08:28:03 -04:00
Andrew Lamb
a2533c20fe
Changelog for version 0.37.0 (#953) 2023-08-22 08:23:43 -04:00
Marko Grujic
1ea8858575
Table time travel clause support, add visit_table_factor to Visitor (#951) 2023-08-22 06:06:32 -04:00
ehoeve
9500649c35
Add support for MySQL auto_increment offset (#950) 2023-08-21 16:25:32 -04:00
Ophir LOJKINE
41e47cc013
add a test for mssql table name in square brackets (#952) 2023-08-21 13:21:45 -04:00
Forbes Lindesay
9a39afbe07
feat: support more Postgres index syntax (#943) 2023-08-17 11:47:11 -04:00
r.4ntix
a49ea1908d
feat: add ALTER ROLE syntax of PostgreSQL and MS SQL Server (#942) 2023-08-17 08:05:54 -04:00
Andrew Lamb
a7d28582e5
Minor: clarify the value of the special flag (#948) 2023-08-17 06:45:18 -04:00
ehoeve
83e30677b0
Add support for table-level comments (#946)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-08-17 06:44:55 -04:00
Jeremy Maness
8bbb85356c
Fix SUBSTRING from/to argument construction for mssql (#947) 2023-08-17 06:17:57 -04:00
Kikkon
173a6db818
Fix: use Rust idiomatic capitalization for newly added DataType enums (#939) 2023-08-07 10:55:42 -04:00
liadgiladi
eb4be98980
Support DROP TEMPORARY TABLE, MySQL syntax (#916) 2023-08-07 10:54:24 -04:00
Ophir LOJKINE
10a6ec5637
Fix "BEGIN TRANSACTION" being serialized as "START TRANSACTION" (#935) 2023-07-27 07:32:55 -04:00
Kikkon
0ddb853410
feat: support pg type alias (#933) 2023-07-27 06:20:24 -04:00
Ophir LOJKINE
53593f1982
Fix parsing of datetime functions without parenthesis (#930) 2023-07-26 15:47:02 -04:00
Andrew Lamb
f60a6f758c chore: Release sqlparser version 0.36.1 2023-07-21 05:16:48 -05:00
Andrew Lamb
91ef061254
Changelog for 0.36.1 (#928) 2023-07-21 06:00:48 -04:00
Andrew Lamb
3a412152b9
fix parsing of identifiers after % symbol (#927) 2023-07-21 05:55:41 -04:00
Andrew Lamb
e36b34d8cc chore: Release sqlparser version 0.36.0 2023-07-19 17:31:43 -04:00
Andrew Lamb
a452054111
CHANGELOG for 0.36.0 (#924) 2023-07-19 17:29:21 -04:00
canalun
f98a2f9dca
feat: mysql no-escape mode (#870)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-07-19 16:36:52 -04:00
parkma99
eb288487a6
Support UNION (ALL) BY NAME syntax (#915) 2023-07-18 17:15:05 -04:00
Andrew Lamb
c45451850c
Clean up JSON operator tokenizing code (#923) 2023-07-17 16:09:55 -04:00
Igor Izvekov
df45db1375
fix: parsing JsonOperator (#913) 2023-07-17 15:03:48 -04:00
Igor Izvekov
c8b6e7f2c7
feat: comments for all operators (#917) 2023-07-17 14:42:28 -04:00
Andrew Lamb
d6ebb58b96
Fix dependabot by removing rust-toolchain toml (#922) 2023-07-17 14:34:54 -04:00
JIN-YONG LEE
653346c4d6
Upgrade bigdecimal to 0.4.1 (#921) 2023-07-17 14:21:45 -04:00
Andrew Lamb
4efe55dd8a
Remove most instances of #[cfg(feature(bigdecimal))] in tests (#910) 2023-07-17 14:19:51 -04:00
Igor Izvekov
a50671d95d
feat: support PGOverlap operator (#912) 2023-07-06 09:27:18 -04:00
Jay Zhan
20ac38b4da
Support multi args for unnest (#909)
Signed-off-by: jayzhan211 <jayzhan211@gmail.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-06-30 16:50:46 -04:00
liadgiladi
f05f71e20d
Support ALTER VIEW, MySQL syntax (#907)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-06-29 13:33:51 -04:00
Robert Pack
9effeba0d8
feat: add deltalake keywords (#906) 2023-06-29 13:30:21 -04:00
Andrew Lamb
efd8cb7fd1 chore: Release sqlparser version 0.35.0 2023-06-23 10:54:52 -04:00
Andrew Lamb
631eddad78
Update CHANGELOG.md for version 0.35.0 (#904) 2023-06-23 10:53:18 -04:00
parkma99
04c9fbaead
update parse STRICT tables (#903)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-06-23 10:48:04 -04:00
Igor Izvekov
8877cbafa6
fix: unary negation operator with operators: Mul, Div and Mod (#902) 2023-06-22 11:15:31 -04:00
delsehi
f72b5a5d9b
Support basic CREATE PROCEDURE of MSSQL (#900)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-06-22 11:09:14 -04:00
dawg
75f18ecfda
Add support for DuckDB's CREATE MACRO statements (#897) 2023-06-21 15:12:58 -04:00
Jeremy Dyer
2296de2bc4
Add fn support_group_by_expr to Dialect trait (#896) 2023-06-15 09:10:56 -04:00
Sam Rijs
2b37e4ae6e
Add support for CREATE TYPE (AS) statements (#888)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-06-08 06:56:39 -04:00
dependabot[bot]
e8cad6ab65
Update criterion requirement from 0.4 to 0.5 in /sqlparser_bench (#890)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-24 17:41:59 -04:00
Andrew Lamb
4607addf4d chore: Release sqlparser version 0.34.0 2023-05-19 09:47:43 -04:00
Andrew Lamb
adfa37d565
Update CHANGELOG for 0.34.0 release (#884) 2023-05-19 09:45:23 -04:00
Andrew Lamb
f740d528da
Fix merge conflict (#885) 2023-05-18 15:28:11 -04:00
Berkay Şahin
ef46cd3752
Named window frames (#881)
* after over clause, named window can be parsed with window ... as after having clause

* Lint errors are fixed

* Support for multiple windows

* fix lint errors

* simplifications

* rename function

* Rewrite named window search in functional style

* Test added and some minor changes

* Minor changes on tests and namings, and semantic check is removed

---------

Co-authored-by: Mustafa Akur <mustafa.akur@synnada.ai>
Co-authored-by: Mehmet Ozan Kabak <ozankabak@gmail.com>
2023-05-18 15:00:24 -04:00
Mustafa Akur
1b86abebe2
Add support for first, last aggregate function parsing (#882)
* Add order by parsing to functions

* Fix doc error

* minor changes
2023-05-18 14:59:14 -04:00
eitsupi
33b12acce7
feat: add DuckDB dialect (#878)
* feat: add DuckDB dialect

* formatting

* fix conflict

* support // in GenericDialect

* add DucDbDialect to all_dialects

* add comment from suggestion

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* fix: support // in GenericDialect

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-05-18 14:57:29 -04:00
Maciej Obuchowski
3be19c7666
truncate: table as optional keyword (#883)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2023-05-18 14:55:02 -04:00
eitsupi
097e7ad56e
feat: Support MySQL's DIV operator (#876)
* feat: MySQL's DIV operator

* fix: do not use `_` prefix for used variable

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-05-17 13:26:14 -04:00
Maximilian Roos
feaa13c9a9
feat: Add custom operator (#868)
* feat: Add custom operator

From #863

- It doesn't parse anything — I'm not sure how to parse ` SELECT 'a' REGEXP '^[a-d]';` with `REGEXP` as the operator... (but fine for my narrow purpose)
- If we need tests, where would I add them?

* Update src/ast/operator.rs

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-05-17 13:12:50 -04:00
Jeffrey
4559d87a82
Add parse_multipart_identifier function to parser (#860)
* Add parse_multipart_identifier function to parser

* Update doc for parse_multipart_identifier

* Fix conflict
2023-05-17 13:04:57 -04:00
Mustafa Akur
482a3ad417
Add support for multiple expressions, order by in aggregations (#879)
* Add support for multiple expressions, order by in aggregations

* Fix formatting errors

* Resolve linter errors
2023-05-17 13:04:33 -04:00
Andrew Kane
ae3b5844c8
Include license file in published crate (#871) 2023-05-09 20:48:57 -04:00
Armin Primadi
f15da8772e
Make Expr::Interval its own struct (#872)
* Make Expr::Interval its own struct

* Add test interval display

* Fix cargo fmt
2023-05-09 20:42:03 -04:00
Okue
b29b551fa1
Fix tiny typo in custom_sql_parser.md (#864) 2023-05-02 07:08:38 -04:00
Andrew Lamb
be85f54ca3
Fix logical merge conflict (#865) 2023-05-02 07:07:56 -04:00
Armin Primadi
0ff863b2c7
Add support for query source in COPY .. TO statement (#858)
* Add support for query source in COPY .. TO statement

* Fix compile error
2023-05-01 15:39:18 -04:00
Aljaž Mur Eržen
0113bbd924
Test trailing commas (#859)
* test: add tests for trailing commas

* tweaks
2023-05-01 08:31:17 -04:00
Aljaž Mur Eržen
3b1076c194
Support DISTINCT ON (...) (#852)
* Support "DISTINCT ON (...)"

* a test

* fix the merge
2023-04-27 15:34:54 -04:00
AviRaboah
f72e2ec382
Support multiple-table DELETE syntax (#855) 2023-04-27 11:41:20 -04:00
Andrew Lamb
5ecf633e31
Add dialect_from_str and improve Dialect documentation (#848)
* Add `dialect_from_str` and improve `Dialect` documentation

* cleanup

* fix compilation with nostd
2023-04-27 11:37:11 -04:00
pawel.leszczynski
d8af92536c
support COPY INTO in snowflake (#841)
Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
2023-04-27 11:30:48 -04:00
AviRaboah
3e92ad349f
Support identifiers beginning with digits in MySQL (#856) 2023-04-26 09:27:04 -04:00
Brian Anglin
6b2b3f1f6c
Adds clickhouse to example (#849) 2023-04-12 15:04:46 -04:00
Andrew Lamb
00719e3cf3 (cargo-release) version 0.33.0 2023-04-10 12:13:03 -04:00
Andrew Lamb
28e558c286
Changelog for 0.33.0 (#846)
* Changelog for `0.33.0`

* typo
2023-04-10 12:11:14 -04:00
Coby Geralnik
04d9f3af2e
Added support for Mysql Backslash escapes (enabled by default) (#844) 2023-04-10 09:56:01 -04:00
Andrew Lamb
00d071286b
Move tests from parser.rs to appropriate parse_XX tests (#845)
* Move tests from parser.rs to appropriate parse_XX tests

* move to postgres tests

* move more tests
2023-04-10 09:48:23 -04:00
Nick Randall
784a19138f
Support "UPDATE" statement in "WITH" subquery (#842)
* fix(WITH): allow "UPDATE" statement in "WITH" subquery"

* add test case

* update test to validate round-trip
2023-04-09 07:41:56 -04:00
pawel.leszczynski
29dea5d017
support PIVOT table syntax (#836)
Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
2023-03-26 07:33:35 -04:00
pawel.leszczynski
79c7ac73df
support CREATE/DROP STAGE for Snowflake (#833)
Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
2023-03-26 07:31:37 -04:00
Maciej Skrzypkowski
a1b7341b87
Non-Latin characters support (#840)
* Non latin characters

---------

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>

* Test for mysql

---------

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
2023-03-23 07:07:17 -04:00
Felix Yan
eb67d489bb
Correct typos in parser.rs (#838) 2023-03-18 11:23:18 -04:00
sam
a8a8e65b7c
PostgreSQL: GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY and GENERATED ALWAYS AS ( generation_expr ) support (#832)
* GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) basic impl - test are failing.

* PostgreSQL GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) and GENERATED ALWAYS AS ( generation_expr ) STORED implementation.
2023-03-16 05:54:00 -04:00
pawel.leszczynski
4ff3aeb040
support IF EXISTS in COMMENT statements (#831)
* support IF EXISTS in COMMENT statements

Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

---------

Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-03-09 08:06:39 -05:00
pawel.leszczynski
548191814c
support snowflake alter table swap with (#825)
Signed-off-by: Pawel Leszczynski <leszczynski.pawel@gmail.com>
2023-03-07 07:16:39 -05:00
Andrew Lamb
9ea396d0da
Improve documentation on verified_* methods (#828) 2023-03-07 07:07:29 -05:00
Andrew Lamb
5f815c2b08 (cargo-release) version 0.32.0 2023-03-06 11:58:23 -05:00
Andrew Lamb
1d358592ab
Changelog for 0.32.0 (#830) 2023-03-06 11:57:27 -05:00
Andrew Lamb
7f4c9132d7
Fix table alias parsing regression in 0.31.0 by backing out redshift column definition list (#827)
* Fix table alias parsing regression

* Revert "Support redshift's columns definition list for system information functions (#769)"

This reverts commit c35dcc93a7.
2023-03-06 11:43:22 -05:00
Ankur Goyal
d69b875367
ClickHouse CREATE TABLE Fixes: add ORDER BY and fix clause ordering (#824)
* Fix ClickHouse (add ORDER BY)

* Improve test case
2023-03-06 09:55:55 -05:00
Mykhailo Bondarenko
1cf913e717
feat: Support PostgreSQL exponentiation. (#813)
* Add Postgres exponent operator

* Parse caret as BinaryOperator::PGExp in PostgreSQL

* Update sqlparser_postgres.rs

* update tests to support PGExp

* cargo fmt

* improve extensibility

* cargo fmt

* redundant code and documentation lionks
2023-03-02 10:39:39 -05:00
Y Togami
fbbf1a4e84
feat: support BIGNUMERIC of bigquery (#811)
* add tests

* bignumeric data type

* bignumeric keyword

* fix doc

* add exact_number_info

* fix doc

* check result string
2023-03-02 10:38:00 -05:00
Ankur Goyal
b45306819c
Add support for trailing commas (#810)
* Add support for trailing commas

* Support trailing commas for brace/bracket

* Andrew's comments
2023-03-02 10:35:46 -05:00
Y Togami
2285bb44ba
chore: fix typo (#822) 2023-03-02 10:32:20 -05:00
Andrew Lamb
b838415276 (cargo-release) version 0.31.0 2023-03-01 14:25:38 -05:00
Andrew Lamb
66ec634c67
Update CHANGELOG for version 0.31 (#820) 2023-03-01 14:23:15 -05:00
Y Togami
58de3c1222
feat: support raw string literal of BigQuery (#812)
* add tests

* feat: parse raw literal of bq

* merge double quoted & single quoted to raw string literal

* Update src/ast/value.rs

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-03-01 14:11:42 -05:00
Y Togami
70917a59ed
feat: SELECT * REPLACE <Expr> AS <Identifier> for bigquery (#798)
* chore: add test for wildcard replace

* feat: define opt_replace for wildcard replace

* fix: modify replace option ast

* fix: add test cases

* chore: fmt

* redefine ast

* feat: parse select replace items

* ci

* Update src/ast/query.rs

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-03-01 13:52:25 -05:00
Y Togami
0c0d088ec2
feat: support byte string literal in bq (#802)
* rebase

* review

* lint
2023-02-19 10:38:03 -05:00
Maciej Skrzypkowski
c35dcc93a7
Support redshift's columns definition list for system information functions (#769)
* parsing of redshift's column definition list for
pg_get_late_binding_view_cols
pg_get_cols
pg_get_grantee_by_iam_role
pg_get_iam_role_by_user

* Renamed ColsDefinition to TableAliasDefinition

added generic dialect

* Tests fixed

* Visitor for IdentPair

* Parsing redshift table alias based on indentifier and
parentheses instead of function name

* fix clippy

---------

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-02-17 14:04:59 -05:00
Maciej Obuchowski
a2fea10f89
snowflake: add support for TRANSIENT keyword (#807)
* snowflake: add support for TRANSIENT keyword

Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>

* fix clippy

---------

Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-02-17 13:55:56 -05:00
Y Togami
79009f5448
feat: support JSON keyword (#799)
* feat: support json keyword for bigquery

* chore: fix test

---------

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-02-17 13:46:30 -05:00
Maciej Skrzypkowski
488e8a8156
Support MySQL Character Set Introducers (#788)
* MySQL Character Set Introducers

* Documentation fix

* Parsing string introducer from Token::word

* Fixed lint

* fix clippy

---------

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2023-02-17 13:38:43 -05:00
Y Togami
b31ede7733
chore: fix clippy error in ci (#803)
* chore: fix clippy error in ci

* chore: fix fmt
2023-02-17 13:24:50 -05:00
Ziinc
4955863bdf
fix: handle bigquery offset in map key (#797)
* fix: handle bigquery offset in map key

* chore: add in more comments and tests

* chore: fix all linting and compilation warnings
2023-01-21 12:05:59 -05:00
SARDONYX
ca939413f2
fix(Dialect): fix a typo (precendence -> precedence) (#794)
* fix(Dialect): fix a typo

* fix: fix a typo in tests
2023-01-15 05:31:49 -05:00
Ophir LOJKINE
3f874f4ab8
use post_* visitors for mutable visits (#789)
My initial implementation of mutable visitors closely matched the existing immutable visitor implementations,
and used pre_* visitors (a mutable expression was first passed the visitor, then its children were visited).

After some initial usage, I realize this actually impractical, and can easily lead to infinite recursion when one isn't careful.
For instance a mutable visitor would replace x by f(x),
then would be called again on the nested x and result in f(f(x)),
then again resulting in f(f(f(x))), and so on.

So, this commit changes the behavior of the visit_*_mut functions to call the visitor on an expression only
once all of its children have been visited.

It also makes the documentation more explicit and adds an example.
2023-01-09 17:04:00 -05:00
Justin Joyce
82cf554394
Add User (#787) 2023-01-09 17:00:55 -05:00
Andrew Lamb
260a012f8c (cargo-release) version 0.30.0 2023-01-02 10:47:00 -05:00
Andrew Lamb
d0ef564fa1
Changelog for 0.30.0 (#786) 2023-01-02 10:46:27 -05:00
Andrew Lamb
204bdc5b62
Fix logical conflict (#785) 2023-01-02 10:40:42 -05:00
Jeffrey
17f604f757
Support RENAME for wildcard SELECTs (#784) 2023-01-02 10:29:06 -05:00
Jeffrey
98403c07b1
Allow parsing of mysql empty row inserts (#783) 2023-01-02 06:51:13 -05:00
Ophir LOJKINE
524b8a7e7b
Add a mutable visitor (#782)
* Add a mutable visitor

This adds the ability to mutate parsed sql queries.
Previously, only visitors taking an immutable reference to the visited structures were allowed.

* add utility functions for mutable visits

* bump version numbers
2023-01-02 06:48:20 -05:00
Andrew Lamb
86d71f2109 (cargo-release) version 0.29.0 2022-12-29 08:07:19 -06:00
Andrew Lamb
890062c36d
Changelog for 29.0.0 (#780)
* Changelog for 29.0.0

* updates
2022-12-29 09:06:17 -05:00
Andrew Lamb
87df09be18
Improve docs and add examples for Visitor (#778)
* Improve docs and add examples for Visitor

* Update src/ast/visitor.rs

Co-authored-by: Raphael Taylor-Davies <1781103+tustvold@users.noreply.github.com>

* Update src/ast/visitor.rs

Co-authored-by: Raphael Taylor-Davies <1781103+tustvold@users.noreply.github.com>

Co-authored-by: Raphael Taylor-Davies <1781103+tustvold@users.noreply.github.com>
2022-12-29 08:56:41 -05:00
Andrew Lamb
fc503e08c9
Add a backlink from sqlparse_derive to sqlparser and publishing instructions (#779)
* Add backlink to sqlparser-rs in derive docs

* Update release docs for sqlparser_derive
2022-12-29 07:55:42 -05:00
Jeffrey
cf3fe64af6
ParserError if nested explain (#781) 2022-12-29 07:55:10 -05:00
Andrew Lamb
b93d82dfca
Fix cargo docs / warnings and add CI check (#777)
* Fix all rustdoc links

* Add docs CI check

* workflow

* test error

* fix yml

* fix yml

* Revert "test error"

This reverts commit 96a40a88a3.

* fix

* more
2022-12-29 07:53:51 -05:00
Alex Vasilev
072ccc0d76
feat: dollar-quoted strings support (#772)
* feat: support dollar-quoted strings

* remove comment

* unused code

* removed debugging

* added tests

* fmt

* clippy

* updated tests
2022-12-29 07:52:17 -05:00
Andrew Lamb
0c9ec40082
Document new features, update authors (#776) 2022-12-28 11:13:25 -05:00
Andrew Lamb
751046de7d
Improve Readme (#774) 2022-12-28 10:49:51 -05:00
Raphael Taylor-Davies
dec3c2b818
Add derive based AST visitor (#765)
* Add derive based AST visitor

* Fix BigDecimal

* Fix no visitor feature

* Add test

* Rename visit_table to visit_relation

* Review feedback

* Add pre and post visit

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-12-28 10:07:12 -05:00
김진성 Kim Jinsung
3e990466f8
Support CREATE TABLE ON UPDATE <expr> Function (#685)
* feat : OnUpdate Function Implement

* feat : add GenericDialect Options
2022-12-28 08:59:09 -05:00
Andrew Lamb
b1a000f149
Standardize comments on parsing optional keywords (#773) 2022-12-28 08:52:12 -05:00
henry
61c661c234
Support ALTER INDEX {INDEX_NAME} RENAME TO {NEW_INDEX_NAME} (#767)
* test: add a case `rename_index`

* feat: add AlterIndex match arm

* fix: remove todo with self.expected

* chore: add comment to unreachable
2022-12-28 08:35:27 -05:00
Jeffrey
f0870fd315
Enable grouping sets parsing for GenericDialect (#771) 2022-12-28 08:31:39 -05:00
Andrew Lamb
79d0baad73
Add configurable recursion limit to parser, to protect against stack overflows (#764) 2022-12-28 08:29:51 -05:00
Jeffrey
2c20ec0be5
Support parsing scientific notation (such as 10e5) (#768) 2022-12-28 08:28:53 -05:00
zidaye
2d801c9fb6
Support DROP FUNCTION syntax (#752)
* drop function

* update  and  to Option

* fix review

* update

* fmt
2022-12-28 07:57:51 -05:00
Audun Skaugen
3d5cc54dcf
Generalize conflict target (#762)
Postgres supports `ON CONFLICT ON CONSTRAINT <constraint_name>` to
explicitly name the constraint that fails. Support this.
2022-12-17 07:38:57 -05:00
Audun Skaugen
6d6eb4bc9b
Support json operators @> <@ #- @? and @@
postgres supports a bunch more json operators. See
https://www.postgresql.org/docs/15/functions-json.html

Skipping operators starting with a question mark for now, since those
are hard to distinguish from placeholders without more context.
2022-12-14 14:54:56 -05:00
Audun Skaugen
fb02344131
Generalize locking clause (#759)
Postgres supports more generalized locking clauses, for example:
FOR UPDATE OF <table_name> SKIP LOCKED

also, multiple locking clauses. Generalize the parser to support these.

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-12-13 17:19:07 -05:00
zidaye
6c545195e1
support create function definition with $$ (#755)
* support create function definition using '2700775'

* fix warn
2022-12-13 17:15:33 -05:00
Ziinc
d420001c37
fix: unnest join constraint with alias parsing for BigQuery dialect (#732)
* fix: unnest join constraint with alias parsing for BigQuery dialect

* chore: fix failing tests
2022-12-13 16:44:45 -05:00
Andrew Lamb
650c53dc77
Add negative test for except clause on wildcards (#746) 2022-12-07 12:19:43 -05:00
yuval-illumex
01fd20f0a3
Support the type key (#750) 2022-12-06 16:07:53 -05:00
Wei-Ting Kuo
bda8268e56
add keyword NANOSECOND (#749) 2022-12-06 15:29:41 -05:00
Ankur Goyal
813f4a2eff
Introduce location tracking in the tokenizer and parser (#710)
* Add locations

* Add PartialEq

* Add PartialEq

* Add some tests

* Fix rebase conflicts

* Fix clippy

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-12-05 14:47:42 -05:00
Andrew Lamb
512a159f08 (cargo-release) version 0.28.0 2022-12-05 14:26:15 -05:00
Andrew Lamb
84291088d9
CHANGELOG.md for 0.28.0 (#747) 2022-12-05 14:21:06 -05:00
Augusto Fotino
b3688513eb
feat: add support for except clause on wildcards (#745) 2022-12-05 14:03:59 -05:00
Runji Wang
5b53df97c4
Support postgres CREATE FUNCTION (#722)
* support basic pg CREATE FUNCTION

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* support function argument

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* fix display and use verify in test

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* support OR REPLACE

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* fix compile error in bigdecimal

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* unify all `CreateFunctionBody` to a structure

Signed-off-by: Runji Wang <wangrunji0408@163.com>

Signed-off-by: Runji Wang <wangrunji0408@163.com>
2022-12-01 16:08:49 -05:00
Andrew Lamb
f621142f89
Clean up some redundant code in parser (#741) 2022-12-01 13:12:27 -05:00
Sarah Yurick
528b3f2234
Support CREATE TABLE x AS TABLE y (#704)
* first commit

* fix style and edit test

* fix test?

* remove unnecessary logic

* refactor implementation

* codestyle

* add schema support

* codestyle and lint

* Apply suggestions from code review

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* PartialOrd and Ord

* clean up parser logic

* codestyle and lint

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-12-01 09:56:14 -05:00
Aljaž Mur Eržen
8e1c90c0d8
Support MySQL ROWS syntax for VALUES (#737)
* Adapt VALUES to MySQL dialect

* Update src/ast/query.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* remove *requirement* for ROW

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-12-01 09:46:55 -05:00
Andrew Lamb
faf75b7161 fix logical conflict 2022-11-30 13:34:31 -05:00
zidaye
042effdf14
update on conflict method (#735) 2022-11-30 13:33:33 -05:00
yuval-illumex
a422116b89
inital commit (#736) 2022-11-30 13:33:15 -05:00
Andrew Lamb
77eddfcc8d
minor cleanup to avoid is_ok() (#740) 2022-11-30 19:25:17 +01:00
Andrew Lamb
bd35273789
Cleanup: avoid using unreachable! when parsing semi/anti join (#738) 2022-11-30 19:25:02 +01:00
Andrew Lamb
b17c44a64a
Docs: Add an example to clarify semantic analysis (#739) 2022-11-30 19:24:13 +01:00
Han YANG
e22aa78315
fix: handle nested comments (#726) 2022-11-30 13:22:29 -05:00
mao
316359760d
Support USING method when creating indexes. (#731)
* fix: create index using function

* fix: code style

Co-authored-by: yangjiaxin <yangjiaxin@qianxin.com>
2022-11-30 13:17:38 -05:00
Tao Wu
7101e0021f
feat: add method to get current parsing index (#728) 2022-11-30 13:14:47 -05:00
Augusto Fotino
6f48fc9acb
docs: add information about parting semantic logic to README.md (#724) 2022-11-30 13:03:10 -05:00
mingmwang
96bca38fae
Support SEMI/ANTI JOIN syntax (#723) 2022-11-30 12:57:45 -05:00
Andrew Lamb
1f22ea74ae fix: logical conflicts 2022-11-30 12:55:55 -05:00
Augusto Fotino
fa6bd01b19
Support EXCLUDE support for snowflake and generic dialect (#721)
The exclude clause can be used after a possibly qualified on SELECT
2022-11-30 12:29:43 -05:00
Augusto Fotino
3df0e444c8
Add 'compression' as keyword (#720) 2022-11-30 12:26:35 -05:00
Augusto Fotino
5e1d9f8d6e
Derive PartialOrd, Ord, and Copy whenever possible (#717)
This allow other projects to use our structures inside others that need
those.
2022-11-30 12:25:59 -05:00
Paul McGee
c429197340
tiny typo (#709) 2022-11-30 12:24:10 -05:00
Augusto Fotino
09d53623bc
Support MATCH AGAINST (#708)
Support added for both MySQL and Generic dialects.
2022-11-30 12:16:50 -05:00
Augusto Fotino
886875f3bf
Support for IF NOT EXISTS in ALTER TABLE ADD COLUMN (#707) 2022-11-29 15:37:14 -05:00
Wei-Ting Kuo
bae682255d
add set time zone sometimezone as a exception while parsing keyword::set (#727)
* add set time zone sometimezone as a exception while parsing keyword::set

* remove redundant parentheses

* add Statement::SetTimeZone

* delete useless comments
2022-11-28 16:16:08 -05:00
mao
10652b61b4
fix: Supports updating valid column names whose names are the same as… (#725)
* fix: Supports updating valid column names whose names are the same as keywords

* fix: warning
2022-11-27 07:29:09 -05:00
Sarah Yurick
57083a0df1
Fix interval parsing logic and precedence (#705)
* initial fix

* add comma

* add test

* style

* add more tests

* codestyle fix
2022-11-22 07:45:47 -05:00
unvalley
4b1dc1abf7
Support UPDATE ... FROM ( subquery ) in some dialects (#694)
* Apply UPDATE SET FROM statement for some dialects

* Add GenericDialect to support

* Test SnowflakeDialect

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-11-11 16:37:09 -05:00
Andrew Lamb
0d91662c88 (cargo-release) version 0.27.0 2022-11-11 16:35:41 -05:00
Andrew Lamb
6a847107ce
Update CHANGELOG for 0.27.0 release (#706) 2022-11-11 16:34:40 -05:00
main()
814367a6ab
Implement ON CONFLICT and RETURNING (#666)
* Implement RETURNING on INSERT/UPDATE/DELETE

* Implement INSERT ... ON CONFLICT

* Fix tests

* cargo fmt

* tests: on conflict and returning

Co-authored-by: gamife <gamife9886@gmail.com>
2022-11-11 16:15:31 -05:00
José Duarte
ae1c69034e
Fix broken DataFusion link (#703) 2022-11-11 16:15:05 -05:00
Augusto Fotino
65c5a37bce
feat: add precision for TIME, DATETIME, and TIMESTAMP data types (#701)
Now all those statements are both parsed and displayed with precision
and timezone info. Tests were added to the ones presented in the ANSI
standard.
2022-11-11 16:06:57 -05:00
Augusto Fotino
cdf4447065
feat: add FULLTEXT option on create table for MySQL and Generic dialects (#702) 2022-11-11 16:03:39 -05:00
SuperBo
87b4a168cb
Parse ARRAY_AGG for Bigquery and Snowflake (#662) 2022-11-11 15:25:07 -05:00
omer-shtivi
0428ac742b
Add MySql, BigQuery to all dialects (#697)
* Add MySql, BigQuery to all dialects

* move unsupported on mysql from common
2022-11-07 15:32:47 -05:00
unvalley
f7817bc7c2
Support DISTINCT for SetOperator (#689)
* Update SetOperation field all to op_option

* Implement parse_set_operator_option

cargo fmt

Fix parse_set_operator_option after next_token

* Add test for parsing union distinct

* Rename to SetQualifier and fix fmt space

* Add None to SetQualifier

* Update parse method

* Rename to SetQuantifier

* Rename parse_set_operator_option parse_set_operator

* Fix test to parse union, except, intersect

* Add some comments to SetQuantifier

* Fix comment
2022-11-07 07:05:59 -05:00
yuval-illumex
0f7e144890
Support the ARRAY type of Snowflake (#699)
* Snowflake Array

* Use the array data type

* Try to fix build

* Try to fix build

* Change Array to option

* Remove unused import
2022-11-04 10:25:25 -04:00
sam
bbf32a9e81
Support create sequence with options INCREMENT, MINVALUE, MAXVALUE, START etc. (#681)
* Creat sequence options model

[ INCREMENT [ BY ] increment ]
    [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
    [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
    [ OWNED BY { table_name.column_name | NONE } ]

* Fix for format! not avalable in --target thumbv6m-none-eabi

* Fix for format! not avalable in --target thumbv6m-none-eabi

* Fix for format! not avalable in --target thumbv6m-none-eabi

* Fix for format! not avalable in --target thumbv6m-none-eabi

* Updated parser for sequence options

* Updated parser for sequence options

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-11-03 09:16:43 -04:00
yuval-illumex
93a050e5f0
Snowflake: Support semi-structured data (#693)
* Support parse json in snowflake

* MR Review

* Lint

* Try to fix right as value

* Fix tests

* Fix lint

* Add generic dialect

* Add support in key location
2022-11-02 12:05:35 -04:00
ding-young
27c3ec87db
Support ALTER TABLE DROP PRIMARY KEY (#682)
* parse alter table drop primary key

* cargo nightly fmt

* add Dialect validation
2022-11-02 10:15:33 -04:00
AugustoFKL
1b3778e2d5
feature!: added NUMERIC and DEC ANSI data types, and now the DECIMAL (#695)
type prints DECIMAL instead of NUMERIC.

BREAKING CHANGE: enum DATA TYPE variants changed, changing any API that
uses it.
2022-10-31 15:22:34 -04:00
Sarah Yurick
f0646c8c1a
add Date keyword (#691) 2022-10-31 15:20:57 -04:00
dependabot[bot]
b671dc62d3
Update simple_logger requirement from 2.1 to 4.0 (#692)
Updates the requirements on [simple_logger](https://github.com/borntyping/rust-simple_logger) to permit the latest version.
- [Release notes](https://github.com/borntyping/rust-simple_logger/releases)
- [Commits](https://github.com/borntyping/rust-simple_logger/compare/v2.1.0...v4.0.0)

---
updated-dependencies:
- dependency-name: simple_logger
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-30 07:28:37 -04:00
Ning Sun
914810d366
Modifier support for Custom Datatype (#680)
* feat: add support for custom types with argument

* refactor: add support for number and string as type arguments

* fix: ignore CustomWithArgs when parsing TypedString

* refactor: merge CustomWithArgs into Custom

* refactor: rename arguments to modifiers
2022-10-20 15:27:15 -04:00
Andrew Lamb
2c266a437c (cargo-release) version 0.26.0 2022-10-19 17:39:37 -04:00
Andrew Lamb
b525c9f2f7
Add changelog for 0.26.0 (#679) 2022-10-19 17:35:37 -04:00
AugustoFKL
2aba3f8c91
Adding MySQL table option {INDEX | KEY} to the CREATE TABLE definiton (partial). (#665)
Theoretically the behavior should be the same as CREATE INDEX, but we
cannot make that assumption, so the parse is (almost) identical as the
input.

Breaking changes:
- Now HASH and BTREE are KEYWORDS, and using them as names can result in
  errors.
- Now 'KEY' and 'INDEX' column names start the parsing of a table constraint if unquoted for the Generic dialect. This results in possible conficts if canonical results are compared for all dialects if a column is named 'key' without quotes.
2022-10-19 17:24:38 -04:00
sam
e3c936a6ce
mod, parser and test cases for CREATE [ { TEMPORARY | TEMP } ] SEQUENCE [ IF NOT EXISTS ] (#678) 2022-10-19 17:21:17 -04:00
sam
b32cbbd855
Support drop sequence statement (#673)
* Add ObjectType Sequence

* Drop sequence test cases added.

* Parser and Drop statement Display updated.

* Parser and Drop statement Display updated.

* Fix compile errors

* add new test case
2022-10-15 08:04:19 -04:00
AugustoFKL
b42632fa0d
Support for ANSI CHARACTER LARGE OBJECT[(p)] and CHAR LARGE OBJECT[(p)]. (#671)
Add tests for both and `CLOB[(p)]`.
2022-10-15 07:55:08 -04:00
Francis Du
a59874136d
Support cache/uncache table syntax (#670)
* feat: support cache/uncache table syntax

* fix: support the full cache table syntax
2022-10-15 07:53:43 -04:00
Mustafa akur
427bec4ccc
Support for INTERVAL inside window frames (#655)
* Add support to for INTERVAL inside window queries

* Remove the unnecessary ancillary struct Interval

* Convert Window Frame Bound to Expr

* remove unnecessary changes

* remove unnecessary changes

Co-authored-by: Mehmet Ozan Kabak <ozankabak@gmail.com>
2022-10-15 06:34:52 -04:00
AugustoFKL
cacdf3305f
Add support for unit on char length units for small character string types. (#663)
This results in complete support for ANSI CHARACTER, CHAR, CHARACTER VARYING,
CHAR VARYING, and VARCHAR.
2022-10-11 08:54:15 -04:00
AugustoFKL
777672625f
Replacing the two booleans from 'SET ROLE' to a single enum. (#664)
This way, we don't rely on the parser to have valid structures for that
statement, as the structure itself is valid.
2022-10-10 17:14:37 -04:00
AugustoFKL
a9939b0a4f
Enum to handle exact number precisios (#654) 2022-10-08 05:59:11 -04:00
AugustoFKL
a3194ddd52
Create table builder structure (#659)
* Create table builder structure

* Adding comments and examples and adjusting file structure
2022-10-07 16:57:10 -04:00
AugustoFKL
6392a216f0
Replacing 'disable-publish=true' flag by 'public=false', to allow compatibility with recent cargo-release versions (#660) 2022-10-07 16:56:27 -04:00
Ophir LOJKINE
f2b0efec0c
clippy fixes (#656) 2022-10-07 16:41:33 -04:00
Andrew Lamb
e7fb3d4fa7
Correct typo in readme (#658) 2022-10-06 15:21:56 -04:00
Sarah Yurick
cb397d19f9
Support CEIL(expr TO DateTimeField) and FLOOR(expr TO DateTimeField) (#635)
* support ceil/floor to datetime

* Update mod.rs

* Update parser.rs

* murphys law

* Update sqlparser_common.rs

* possible fix?

* remove question mark

* ceil to floor

* Update mod.rs

* Apply suggestions from code review

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* refactor into parse_ceil_floor_expr

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-10-06 15:21:25 -04:00
AugustoFKL
f7f14df4b1
647 Adding all ansii character string types, parsing them, and differentiating between each one (#648) 2022-10-04 06:42:29 -04:00
Andrew Lamb
977cdb2270 (cargo-release) version 0.25.0 2022-10-03 09:11:58 -04:00
Andrew Lamb
97a52cb85b
Changelog for 0.25.0 release (#651)
* Prepare for 0.25.0 release

* fixip
2022-10-03 09:01:26 -04:00
AugustoFKL
1ced0f6304
645 New schema name structure (#646) 2022-10-03 08:38:01 -04:00
AugustoFKL
95464ec72c
Change TIMESTAMP and TIME parsing so that time zone information is preserved (#641)
* 640 Fixing time zone printing format for TIMESTAMP and TIME

* 640 Removing unnecessary changes

* Update src/ast/data_type.rs

Fix comment typo

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-10-03 08:37:17 -04:00
AugustoFKL
3beecc0a7a
Correct order of arguments in LIMIT x,y , restrict to MySql and generic dialects (#642)
* 613 Fixing MySQL LIMIT syntax

* 613 Reducing logic to real case scenario

* 613 Adding syntax to generic dialect
2022-10-01 17:23:06 -04:00
AugustoFKL
fb5a9747ae
Support optional precision for CLOB and BLOB (#639)
* 638 Adjusting CLOB and BLOB with optional precision

* 638 Adding integration tests to increase coverage

* 638 Adjusting BLOB test
2022-10-01 17:15:47 -04:00
AugustoFKL
300e28bd85
636 Adjusting VARBINARY and BINARY with optional precision (#637) 2022-10-01 16:52:44 -04:00
Andrew Lamb
c2d68255d0 (cargo-release) version 0.24.0 2022-09-28 16:46:33 -04:00
Andrew Lamb
e2a51ad649
Release notes for 0.24.0 (#634)
* Disambiguate CREATE ROLE ... USER and GROUP

* Add changelog for 0.24
2022-09-28 16:34:48 -04:00
Sarah Yurick
d87408bdaf
Parse MILLENNIUM (#633)
* add unknown, is not true/false/unknown

* millennium
2022-09-28 16:26:29 -04:00
AugustoFKL
e951cd5278
#625 adding mediumint support (#630) 2022-09-28 16:26:17 -04:00
AugustoFKL
46b7c03788
Adding DOUBLE PRECISION to data types, parsing it, and tests (#629) 2022-09-28 16:26:11 -04:00
ding-young
6c8f31c367
Fix parsing CLOB, BINARY, VARBINARY, BLOB data type (#618)
* fix(parser): parse clob, binary, varbinary, blob data type

* feat(tests): parse_cast tests for LOB, BINARY datatype
2022-09-28 07:02:30 -04:00
Andrew Lamb
6afd194e94
Disambiguate CREATE ROLE ... USER and GROUP (#628) 2022-09-27 13:56:29 -04:00
Andrew Lamb
2b21da2439
Add test for optional WITH in CREATE ROLE (#627) 2022-09-27 10:23:33 -04:00
Ben Cook
91087fcba0
Support CREATE ROLE and DROP ROLE (#598)
* Parse GRANT ROLE and DROP ROLE

* Gate create role on dialect

* cargo fmt

* clippy

* no-std

* clippy again
2022-09-27 09:58:36 -04:00
Ophir LOJKINE
604f755a59
Fix parse error on some prepared statement placeholders (#604)
sqlparser can now parse all the prepared statement placeholders supported by SQLite:

 - ?
 - ?NNN
 - @VVV
 - :VVV
 - $VVV

See: https://www.sqlite.org/lang_expr.html#varparam

This does not break existing support for postgresql's '@' operator

Fixes #603
2022-09-27 09:58:26 -04:00
ding-young
3ac1bb5b80
Move Value::Interval to Expr::Interval (#609)
* refactor(value): convert Value::Interval to Expr::Interval

* test(sqlparser_common): modify test case

* refactor(parser): rename func parse_interval

* refactor(tests) rename parse_interval test func
2022-09-27 09:30:48 -04:00
dependabot[bot]
d971a029dd
Update criterion requirement from 0.3 to 0.4 in /sqlparser_bench (#611)
Updates the requirements on [criterion](https://github.com/bheisler/criterion.rs) to permit the latest version.
- [Release notes](https://github.com/bheisler/criterion.rs/releases)
- [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bheisler/criterion.rs/compare/0.3.0...0.4.0)

---
updated-dependencies:
- dependency-name: criterion
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-27 09:07:59 -04:00
Maciej Skrzypkowski
d4e5b4d5e8
Support National string literal with lower case n (#612)
* National string literal with lower case n

It's used by Snowflake

* Corrected DB name

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
2022-09-27 09:07:13 -04:00
Alex Qyoun-ae
0724ef13a4
Box Query in Cte (#572) 2022-09-27 09:03:58 -04:00
Daniël Heres
39761b0599
Add optional format for explain (#621)
* Add format for explain

* Add comment
2022-09-26 07:22:03 -04:00
Justin Joyce
495ab59aad
Support SHOW FUNCTIONS (#620)
* support SHOW FUNCTIONS

* Update keywords.rs

* Update mod.rs

* Update sqlparser_common.rs

* Fix CI issues
2022-09-26 08:33:53 +02:00
Wei-Ting Kuo
fccae77c5e
support "set time zone to 'some-timezone'" (#617)
* support "set time zone"

* fix clippy

* fix test cases
2022-09-20 09:44:51 -04:00
Andy Grove
48fa79d744
update changelog (#607) 2022-09-08 20:13:11 -06:00
Andy Grove
fd07a17101 (cargo-release) version 0.23.0 2022-09-08 15:15:40 -06:00
Andy Grove
303f80f168
Add support for aggregate expressions with filters (#585) 2022-09-08 13:08:45 -06:00
Alex Qyoun-ae
0bb49cea99
feat: Support LOCALTIME and LOCALTIMESTAMP time functions (#592) 2022-08-30 10:15:39 -06:00
Andy Grove
bccd63ea07 (cargo-release) version 0.22.0 2022-08-26 17:03:42 -06:00
Andy Grove
0191839176
update changelog for 0.22 (#595) 2022-08-26 16:42:46 -06:00
Ayush Dattagupta
6f55dead53
Add overlay expr (#594)
* Add PLACING keyword to keywords list

* Add high level overlay expr to Expr enum

* Add parsing logic for overlay op

* add ovleray and is not true/false/unknown tests
2022-08-26 15:13:25 -06:00
Wei-Ting Kuo
95fbb55f2c
add with/without time zone (#589) 2022-08-26 15:11:21 -06:00
Andy Grove
72559e9b62
Add ability for dialects to override prefix, infix, and statement parsing (#581) 2022-08-19 05:44:14 -06:00
Andrew Lamb
7c02477151 (cargo-release) version 0.21.0 2022-08-18 14:00:13 -04:00
Andrew Lamb
dcb005e17a
Update changelog (#584) 2022-08-18 13:55:36 -04:00
Dmitry Patsura
6d8aacd85b
feat: Support expression in SET statement (#574)
Co-authored-by: Alex Vasilev <vaspiring@gmail.com>
2022-08-18 13:29:55 -04:00
Andy Grove
eb7f1b005e
Parse LIKE patterns as Expr not Value (#579) 2022-08-18 10:02:54 -06:00
Sarah Yurick
fc71719719
add unknown, is not true/false/unknown (#583) 2022-08-18 07:44:18 -06:00
Seo Sanghyeon
50aafa8dc1
Update Ballista link in README (#576) 2022-08-17 21:26:45 +03:00
Ayush Dattagupta
42c5d43b45
Support TRIM from with optional FROM clause (#573)
* Split trimwhereFlag and trim_char expr to seperate members of Expr::Trim

* update trim parsing logic to handle no flag + char from expr combo

* add tests

* Allow trim flag without trim_what expr

* Add trim flag without trim_what test
2022-08-15 17:58:43 -04:00
Alex Qyoun-ae
31ba0012f7
Support PostgreSQL array subquery constructor (#566) 2022-08-12 14:08:56 -04:00
Andrew Lamb
61dc3e9bf9
Clarify contribution licensing (#570)
* Clarify contribution licensing

* less whitespace
2022-08-11 17:29:27 -04:00
Andrew Lamb
36de9a69c6
Update for new clippy ints (#571) 2022-08-11 17:18:46 -04:00
Ayush Dattagupta
f07063f0cd
Support for SIMILAR TO syntax, change Like and ILike to Expr variants, allow escape char for like/ilike (#569)
* Remove [not]like,[not]ilike from binary operator list

* Add like, ilike and similar as an expr variant. Also adds support for escape char to like/ilike

* Add parsing logic for similar to, update parsing logic for like/ilike

* Add tests for similar to, update tests for like/ilike

* Fix linter warnings

* remove additional copyright license from files

* Add more coverage w/wo escape char for like,ilike,similar to
2022-08-11 15:44:26 -04:00
Alex Qyoun-ae
18881f8fcf
Support SHOW COLLATION (#564) 2022-08-11 09:28:34 -04:00
Dmitry Patsura
54a29e872d
feat: Parse special keywords as functions (current_user, user, etc) (#561)
* feat: Parse special keywors as functions (current_user, user, etc)

* explain special field
2022-08-11 08:30:06 -04:00
Alex Qyoun-ae
b6e36ad760
Support SHOW TABLES (#563) 2022-08-11 08:24:40 -04:00
Dmitry Patsura
221e9c2bab
feat: Support SET NAMES literal [COLLATE literal] (#558)
* feat: Support SET NAMES literal [COLLATE literal]

* feat: Support SET NAMES DEFAULT

* clippy
2022-08-11 06:55:55 -04:00
Yoshiyuki Komazaki
aabafc9fc8
feat: Support trailing commas (#557) 2022-08-11 06:54:04 -04:00
Alex Qyoun-ae
8176561100
Support expressions in LIMIT/OFFSET (#567) 2022-08-11 06:50:18 -04:00
Alex Qyoun-ae
a9db6ed139
Support USE db (#565) 2022-08-11 06:49:20 -04:00
Alex Qyoun-ae
71c3ec057b
Support SHOW COLUMNS FROM tbl FROM db (#562) 2022-08-11 06:42:08 -04:00
Dmitry Patsura
e2b943799a
feat: Initial support for parsing MySQL show variables (#559)
Co-authored-by: Alex Vasilev <vaspiring@gmail.com>
2022-08-11 06:35:59 -04:00
Andrew Lamb
231370a770 (cargo-release) version 0.20.0 2022-08-05 14:10:58 -04:00
Andrew Lamb
bb5e2782b5
Make 0.20.0 release notes (#555) 2022-08-05 14:01:25 -04:00
Jamie Slome
9648a52715
Create SECURITY.md (#546) 2022-08-05 13:54:38 -04:00
Kaushik Iska
1c64129f76
[postgres] Add support for custom binary operators (#548)
* [postgres] Add support for custom binary operators

More details about operators in general are at:
https://www.postgresql.org/docs/current/sql-createoperator.html. This
patch attempts to parse `SELECT` queries that reference an operator
using `OPERATOR(<optional_schema>.<operator_name>)` syntax.

This is a PostgreSQL extension. There are no provisions for user-defined operators in the SQL standard.

* fix code-review comments and ci failures

* Allow custom operator in generic dialects too

* Parse `OPERATOR` as Vec<String>

* fix: std

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-08-05 13:53:58 -04:00
Dmitry Patsura
6c98228e71
feat: Allow to use >> and << binary operators in Generic dialect (#553) 2022-08-05 06:25:57 -04:00
Wei-Ting Kuo
076b587bb2
Support NestedJoin with an alias (#551)
* add alias for nestedjoin

* fmt

* add/modify test cases

* inline nestedjoin instead of macro
2022-08-03 19:41:15 -04:00
Yoshi Togami
e24951e080
feat: support SAFE_CAST for bigquery (#552)
Co-authored-by: togami2864 <yoshiaki.togami@plaid.co.jp>
2022-08-03 09:17:39 -04:00
Andrew Lamb
2a04212e56 (cargo-release) version 0.19.0 2022-07-28 14:54:22 -04:00
Andrew Lamb
ec22e00f81
Update CHANGELOG.md for 0.19.0 (#545) 2022-07-28 14:47:06 -04:00
Andy Richardson
16af309c74
Add support for ClickHouse DDL query syntax (on cluster) (#527)
* Add on_cluster to Statement::CreateTable

* Add printing of on_cluster

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Fix fmt + nostd

* Remove unintended diff

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-07-28 14:44:05 -04:00
Chris Allen
f74753436a
Support for empty array literals (#532)
Co-authored-by: Chris Allen <chrisa@indeed.com>
2022-07-18 19:28:39 +02:00
Chris Allen
7cbbd9188e
Add support for AT TIME ZONE (#539)
* Support for empty array literals

* Added support for AT TIME ZONE

Co-authored-by: Chris Allen <chrisa@indeed.com>
2022-07-18 13:03:01 -04:00
Maciej Obuchowski
4706d8b1d2
delete: add using clause, possibility of using aliases (#541)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-07-18 10:29:03 -04:00
Mike Roberts
93e16e9864
Add support for mysql 'SHOW CREATE VIEW' statement (#536) 2022-07-18 06:10:09 -04:00
5tan
dea7666086
Boxed Query body to save some stack space (#540) 2022-07-16 07:22:45 -04:00
Maciej Obuchowski
5363d4e399
create table: add clone syntax (#542)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-07-16 07:17:02 -04:00
Mykhailo Bondarenko
c2ccc80c28
Count characters instead of bytes (#529)
* Count characters instead of bytes

* cargo fmt

* add tests to PR #529
2022-07-07 13:45:59 -04:00
sivchari
68768530cd
feat: Add WITH OFFSET Alias (#528)
* feat: Add WITH OFFSET Alias

* update: fix with_offset_alias type
2022-06-29 13:29:44 -04:00
Yoshiyuki Komazaki
17c238bda7
feat: Support double quoted string (#530) 2022-06-28 16:41:23 -04:00
Andrey Frolov
f29ce10a1a
Distinguish between INT and INTEGER types (#525)
* support integer

* fmt

* Update src/ast/data_type.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-06-21 09:32:10 -04:00
Andrey Frolov
c884fbc388
add more consistency in ast (#523)
* add more consistency in ast

* refactor styling
2022-06-14 17:02:03 -04:00
Yoshi Togami
d981f70143
fix: Support expr instead of string for argument to interval (#517)
* fix: use expr instead of string in interval

* chore: resolve CI

Co-authored-by: togami2864 <yoshiaki.togami@plaid.co.jp>
2022-06-13 08:35:06 -04:00
Andrey Frolov
99697d26e1
add on update for my sql (#522) 2022-06-13 08:33:10 -04:00
Andrew Lamb
ca15a4edbf (cargo-release) version 0.18.0 2022-06-06 16:53:46 -04:00
Andrew Lamb
3ffdb0bbe8
Update CHANGELOG.md for 0.18.0 (#516) 2022-06-06 16:50:31 -04:00
Dmitry Patsura
d361c3a3a1
feat: Support CLOSE (cursors) (#515) 2022-06-06 16:09:17 -04:00
Dmitry Patsura
3f1c6426f0
feat: Initial support for DECLARE (cursors) (#509) 2022-06-06 07:22:12 -04:00
Dmitry Patsura
66a3082cb6
feat: Support FETCH (cursors) (#510) 2022-06-04 14:24:36 -04:00
Yoshiyuki Komazaki
d19d955d9b
Support DATETIME keyword (#512) 2022-06-04 14:19:57 -04:00
sivchari
aa46e930c5
Support UNNEST as a table factor (#493)
* support unnest

* add test

* fix ast

* Update condition for BigQueryDialect or GenericDialect

I updated condition.
This changes conditionalize parsing for only BigQueryDialect or GenericDialect.

* Add some tests

* fix test
2022-05-27 06:27:51 -04:00
Riccardo Azzolini
d19c6c323c
Fix escaping of trailing quote in quoted identifiers (#505)
* Generalize EscapeSingleQuoteString to arbitrary quote character

* Fix escaping of trailing quote in quoted identifiers

* Add new tests instead of modifying existing tests
2022-05-27 06:25:24 -04:00
Maciej Obuchowski
cc2559c097
hive: add create function syntax (#496)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-05-26 17:30:10 -04:00
Riccardo Azzolini
0fa812bd2b
Fix parsing of COLLATE after parentheses in expressions (#507) 2022-05-25 16:10:38 -04:00
Riccardo Azzolini
901f5b974f
Distinguish between tables and nullary functions in FROM (#506) 2022-05-25 16:01:13 -04:00
Maciej Skrzypkowski
cd66034a4a
MERGE INTO semicolon handling (#508)
* SGA-4181 MERGE INTO semicolon handling

* fixed lint warning

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
2022-05-25 15:48:15 -04:00
mao
09bdb6bb8a
Support placeholders ($ or ?) in LIMIT clause (#494)
* fix: limit $1

* feat: test limit $1

* Update Cargo.toml

* cargo fmt

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-05-25 15:40:30 -04:00
Dmitry Patsura
2c0886d9fe
feat: Support escaped string literals (PostgreSQL) (#502)
* feat: Support escaped string literals (PostgreSQL)

Signed-off-by: Dmitry Patsura <talk@dmtry.me>

* lint

* escape ', \r, \t

* Update src/ast/value.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Update src/tokenizer.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* test: two slashes

* remove dead code

* test: parsing error

* support generic dialect too (for DF)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-05-25 14:42:14 -04:00
Dmitry Patsura
4070f3ec6e
feat: Convert IS TRUE|FALSE to expression (#499) 2022-05-24 09:26:50 -04:00
George Andronchik
a6d7a35dac
feat: support DISCARD [ALL | PLANS | SEQUENCES | TEMPORARY | TEMP] (#500) 2022-05-22 15:44:53 -04:00
Maciej Obuchowski
7ab30d95b0
hive: add support for array<> (#491)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-05-22 15:38:24 -04:00
Maciej Obuchowski
74f92079ac
set: allow negative ident values (#495)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-05-22 15:33:07 -04:00
Andrew Lamb
85e0e5fd39
Add docs for MapAccess (#489)
* Add docs for `MapAccess`

* fix: fmt

* Apply suggestions from code review

Co-authored-by: Dmitry Patsura <zaets28rus@gmail.com>

* touchup

Co-authored-by: Dmitry Patsura <zaets28rus@gmail.com>
2022-05-22 15:26:06 -04:00
Andrew Lamb
11046f66e7
Correct typo: indexs to indexes (#492) 2022-05-22 15:03:48 -04:00
Alex Yaroslavsky
dd805e9a6b
Support unicode whitespace (#482)
* Support unicode whitespace

* Add test
2022-05-15 14:58:56 -04:00
Yoshiyuki Komazaki
97a148aee4
Add BigQuery dialect (#490) 2022-05-10 10:25:27 -04:00
Andrew Lamb
484a7b6da4 (cargo-release) version 0.17.0 2022-05-10 09:26:00 -04:00
Andrew Lamb
acd60d169d
Update changelog for 0.17.0 (#488)
* Update changelog for 0.17.0

* add reference to #466

* Updates for recent merges
2022-05-10 09:23:04 -04:00
Maciej Skrzypkowski
9750841a66
Parse merge source as table factor (#483)
* Parse source of MERGE as table_factor

Some MERGE queries need a table as a soruce,
added proper test showing it

* Clippy fix

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
2022-05-10 06:34:45 -04:00
yuval-illumex
35f5f0be4d
Redshift - Add support in sharp as start of the field name (#485)
* Add support in sharp

* CR Review
2022-05-10 06:34:01 -04:00
Poonai
ed86c6d53d
add support for postgres composite types (#466)
* add support for postgres composite types

Signed-off-by: password <rbalajis25@gmail.com>

* fix composite test for bigdecimal feature

Signed-off-by: password <rbalajis25@gmail.com>
2022-05-09 15:12:22 -04:00
Alex Qyoun-ae
6b2fc8102f
feat: Support TABLE keyword with SELECT INTO (#487) 2022-05-09 14:29:43 -04:00
Maciej Obuchowski
6d057ef4df
set: allow dots in variables by moving to ObjectName (#484)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-05-09 14:21:20 -04:00
Maciej Obuchowski
835bb2f9ad
into keyword is optional (#473)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-05-09 13:08:24 -04:00
Dmitry Patsura
8ef5fc8624
feat: Support ANY/ALL operators (#477)
* feat: Support ANY/ALL operators

* fix lint
2022-05-06 13:32:04 -04:00
Dmitry Patsura
e68bdae5f2
feat: Allow ArrayIndex for GenericDialect (#480)
* feat: Allow ArrayIndex for GenericDialect

* test array index with generic dialect too
2022-05-04 20:20:45 -04:00
Maciej Skrzypkowski
7fc6361fe8
Add Redshift dialect, handle square brackets properly (#471)
* Redshift square bracket handling

We need to detect `[` or `"` for Redshift quotes around indentifier and at the same time exclude
treating JSON paths as indentifer

* RedshiftSqlDialect documentation update

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Renamed _chars to chars

* Fixed warnings

* Missing license

Co-authored-by: Maciej Skrzypkowski <maciej.skrzypkowski@satoricyber.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-05-04 11:11:00 -04:00
Andrew Lamb
a9d7f7af1f
Improve docs for KILL statement (#481) 2022-05-02 17:49:06 -04:00
Dmitry Patsura
f5980cd30f
feat: Support KILL statement (#479) 2022-05-02 14:04:33 -04:00
yuval-illumex
7732c34b19
Add support in IS boolean filter (#474)
* Add support in IS TRUE IS FALSE

* Fix lint

* Add test for is false
2022-05-02 14:02:28 -04:00
Maciej Obuchowski
525ba527bb
snowflake: add qualify expression (#465)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-04-29 14:11:11 -04:00
Andrew Lamb
edad20cbb8
Add negative tests for POSITION (#469) 2022-04-25 07:21:06 -04:00
yuval-illumex
8f4f01e517
Add Support in the "Position" Function (#463)
* Add support in the position function

* Add Test

* Add lint fixes

* Remove if

* Change from to in

* Remove special method for position

* Fix lint

* PR Review
2022-04-25 06:32:16 -04:00
Andrew Lamb
d2487445b7
Add negative test for IN parsing (#468) 2022-04-24 06:48:31 -04:00
George Andronchik
0924870d11
Support global,local, on commit for create temporary table (#456)
* feat: add global,local / on commit for create temp tables

* chore: minor refactor

* chore: clippy fix
2022-04-22 07:58:39 -04:00
yuval-illumex
278345d21a
Add support of NVARCHAR data type (#462)
* Add support of nvarchar data type

* Change the format type with capitals

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Add Test

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-04-20 17:25:50 -04:00
Poonai
d035784bdf
Add support for postgres json operators ->, ->>, #>, and #>> (#458)
* add support for postgres json selection

Signed-off-by: password <rbalajis25@gmail.com>

* fix clippy

Signed-off-by: password <rbalajis25@gmail.com>

* add support for postgres `#>` and `#>>` json operator

* fix clippy

Signed-off-by: poonai <rbalajis25@gmail.com>

* resolve comments

Signed-off-by: password <rbalajis25@gmail.com>
2022-04-19 15:46:56 -04:00
slhmy
8f207db059
Support 'SET ROLE' statement (#455) 2022-04-13 14:45:53 -04:00
Andrew Lamb
7480e89f7b (cargo-release) version 0.16.0 2022-04-03 07:05:16 -04:00
Andrew Lamb
f125a287b5
Update changelog for 0.16.0 (#452) 2022-04-03 07:04:07 -04:00
Runji Wang
bfd416d978
Add support for more postgres COPY options (#446)
* implement parsing COPY statement

* support COPY option syntax before PostgreSQL version 9.0

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* update COPY tests

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* improve docs for COPY

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* test and fix AS in COPY

Signed-off-by: Runji Wang <wangrunji0408@163.com>

* recover original test cases

* fix cargo clippy
2022-04-03 06:37:12 -04:00
slhmy
fd8f2df10d
Support Update Set From statement (#450) 2022-04-02 06:34:59 -04:00
Matthew Turner
803fd6c970
Add CREATE DATABASE test and parsing (#451)
* Add test

* Fix CreateDatabse parsing

* Linting

* Cleanup for code style
2022-04-01 13:32:38 -04:00
Maciej Obuchowski
d38c30e9ff
add SELECT INTO statement variation (#447)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-03-30 16:01:55 -04:00
Matthew Turner
b68e9a3801
Add support for COPY TO (#441)
* Start adding COPY TO

* Fix statement and add tests

* Merge copy statements

* Remove extra line

* Clippy

* Cleanup
2022-03-22 18:21:44 -04:00
Poonai
12a3e97ef3
add support for SAVEPOINT statement (#438) 2022-03-13 03:29:26 -04:00
Simon Liu
497a3b0e1b
Fixed the bug that the access parsing is wrong when multiple query conditions contain arrays or map. (#433) 2022-03-12 14:29:37 -05:00
Maciej Obuchowski
6b55e51101
add support for MERGE statement (#430)
* add support for MERGE statement

Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>

* fix lint errors

Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-03-12 14:28:57 -05:00
Yang Jiang
c688bbb4de
extract operator: add support for week keywords (#436) 2022-03-12 14:17:56 -05:00
Andrew Lamb
481551c075 (cargo-release) version 0.15.0 2022-03-08 13:41:26 -05:00
Andrew Lamb
ad1979146d
Update changelog for 0.15.0 (#431)
* Update changelog for 0.15.0

* Add late breaking additions
2022-03-08 13:34:34 -05:00
Andrew Lamb
a28bbcd74c
Allow array to be used as a function name again (#432)
* Allow `array` to be used as a function

* clarify code, add docstrings

* fix docs

* cleanup

* fmt
2022-03-08 13:25:48 -05:00
Simon Liu
3f5619446f
Support for ClickHouse array types (e.g. [1,2,3]) (#429) 2022-03-08 11:44:32 -05:00
Wataru Kurashima
994b86a45c
mysql unsigned datatype (#428)
* support MySQL UNSIGNED

* fix: 🐛 `unsigned` is not column option

* test: 💍 add `unsigned` test

* fix: 🐛 `unsigned` is not column option

* feat: 🎸 declare unsigned data_types

* feat: 🎸 display unsigned

* fix: 🐛 unsigned is not column type option

* feat: 🎸 parse_data_type can parse unsigned

* feat: 🎸 int or decimal or float is unsigned selectable

* fix: 🐛 FLOAT/DOUBLE/DECIMAL + UNSIGNED is not recommended

https://dev.mysql.com/doc/refman/8.0/en/numeric-type-attributes.html

* test: 💍 add test

* style: 💄 fmt
2022-03-07 17:01:48 -05:00
Maciej Obuchowski
3af3ca07b6
extract operator: add support for Postgres keywords (#427)
Signed-off-by: Maciej Obuchowski <obuchowski.maciej@gmail.com>
2022-03-07 10:03:28 -05:00
Yoshiyuki Komazaki
0d1c5d1205
Support IN UNNEST(expression) (#426)
* feat: support `IN UNNEST(expression)`

* Add test for NOT IN UNNEST
2022-03-01 08:53:01 -05:00
Wataru Kurashima
2ebe18a94e
Support COLLATION keywork on CREATE TABLE (#424)
* support table definition's collate

* add table collate test
2022-02-28 14:04:47 -05:00
Maximilian Roos
b5f37118f1
Update doc reference to Query (#423)
* Update doc reference to Query

I guess it used to be called SQLQuery?
2022-02-28 14:04:09 -05:00
Eli Flanagan
c1703899a7
ci: remove Travis CI (#421)
Removing "dead code"
2022-02-28 14:04:00 -05:00
flaneur
b14c0d5657
add role keyword (#422) 2022-02-28 13:43:48 -05:00
gamife
0b5178d7e7
feat: add FOR UPDATE/FOR SHARE clause (#418)
* feat: add FOR UPDATE/FOR SHARE clause

* refactor: LockType enum variant name

Co-authored-by: gamife <gamife9886@gmail.com>
2022-02-24 06:39:38 +01:00
gamife
899f91b1f6
feat: add arg placeholder (#420)
Co-authored-by: gamife <gamife9886@gmail.com>
2022-02-17 07:55:21 -05:00
gamife
1da49c15c7
Support array expressions such as ARRAY[1,2] , foo[1] and INT[][] (#419)
* feat: add array expression

* test: add back the the existing test

Co-authored-by: gamife <gamife9886@gmail.com>
2022-02-17 07:21:11 -05:00
Andrew Lamb
0d6386e4a3 (cargo-release) version 0.14.0 2022-02-09 09:29:52 -05:00
Andrew Lamb
254e5d1b1e
Update changelog for 0.14 release (#417)
* Update changelog for 0.14 release

* Add other changelog items
2022-02-09 09:27:09 -05:00
Andrew Lamb
d7f4f1aac9
Support MySQL style LIMIT X, Y (#415) 2022-02-09 06:44:51 -05:00
Andrew Lamb
2072ef2031
Clarify maintenance status on README (#416)
* Clarify maintenance status on README

* update review policy

* add a note about error tests
2022-02-09 06:41:51 -05:00
Andrew Lamb
ff558eeb61
Add Expr::tuple + parsing (#414) 2022-02-08 10:54:27 -05:00
Evgeny
8a3544abae
Fix panic with GRANT/REVOKE in CONNECT, CREATE, EXECUTE or TEMPORARY (#401)
* fix inconsistency between parse_grant_permissions and matched keywords

* Make it clear the error is an internal problem

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-02-08 10:50:55 -05:00
tvallotton
c4cbc8340a
Support DROP CONSTRAINT [ IF EXISTS ] <name> [ CASCADE ] (#396)
* adding support for DROP CONSTRAINT [ IF EXISTS ] <name>

* implementing [ CASCADE ] for DROP CONSTRAINT
2022-02-08 10:34:09 -05:00
Jakob Truelsen
e4959696b5
Support CHARSET and ENGINE clauses on CREATE TABLE for mysql (#392)
* Add support for SET and ENUM types

See https://dev.mysql.com/doc/refman/8.0/en/set.html
and https://dev.mysql.com/doc/refman/8.0/en/enum.html

* Add support for mysql ENGINE and DEFAULT CHARSET in CREATE TABLE

See https://dev.mysql.com/doc/refman/8.0/en/create-table.html

* Add support for COMMENT and CHARACTER SET field attributes

See https://dev.mysql.com/doc/refman/8.0/en/create-table.html
2022-02-08 10:08:56 -05:00
Markus Westerlind
34fedf311d
fix: Handle double quotes inside quoted identifiers correctly (#411)
* fix: Handle double quotes inside quoted identifiers correctly

This fixes #410 for standard SQL, however I don't know enough about other dialects to know if they
handle this differently. May need more extensive testing as well.

* refactor: Make quoted identifier parsing a seperate function

* test: Check that quoted identifier tokenization works

Added `pretty_assertions` so that the `assert_eq!` in the tokenization is readable

* test: Check that quoted identifiers work in mysql

* chore: cargo clippy
2022-02-07 10:05:17 -05:00
Poonai
2614576dbf
Add support for FROM <filename>, DELIMITER, and CSV HEADER options for COPY command (#409)
* add additional options for copy command

Signed-off-by: password <rbalajis25@gmail.com>

* cargo fmt

Signed-off-by: password <rbalajis25@gmail.com>
2022-02-07 06:33:28 -05:00
Andrew Lamb
33d4f27bfc
Support OFFSET LIMIT as well as LIMIT OFFSET (#413)
* Inital support in current_timestamp

* Support time functions

* Add Test

* Fix order of offset

* Merge from main

* Fix PR

* Update Test

* Do not allow repeated LIMIT or OFFSET

Co-authored-by: Yuval Shkolar <yuval@illumex.ai>
2022-02-05 07:46:53 -05:00
dependabot[bot]
87509f1dec
Update simple_logger requirement from 1.9 to 2.1 (#403)
Updates the requirements on [simple_logger](https://github.com/borntyping/rust-simple_logger) to permit the latest version.
- [Release notes](https://github.com/borntyping/rust-simple_logger/releases)
- [Commits](https://github.com/borntyping/rust-simple_logger/compare/v1.9.0...v2.1.0)

---
updated-dependencies:
- dependency-name: simple_logger
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2022-02-05 07:33:00 -05:00
Tao Wu
929ef2a4b8
fix: export all methods of parser (#397) 2022-02-05 07:26:09 -05:00
flaneur
d4e6ef597a
add SUPER keyword (#387) 2022-02-05 06:54:00 -05:00
Andrew Lamb
5cbf1e797a
Fix new clippy errors (#412) 2022-02-05 06:53:33 -05:00
yuval-illumex
fbc1d9659b
Support parentheses in DISTINCT clause, CURRENT_TIMESTAMP, CURRENT_TIME, and CURRENT_DATE (#391)
* Inital support in current_timestamp

* Support time functions

* Add Test

* Fix PR

* Fix tests

* Add Support for distinct with parentheses

* Fix nightly
2022-02-05 06:39:35 -05:00
Alex Vasilev
ea0eb1be61
fix: mysql backslash escaping (#373)
* fix: mysql backslash escaping

* fixes
2021-12-23 08:50:33 -05:00
Simon Liu
60ad78dafc
Enable map access for function, add ClickHouse dialect (#382)
* 1 Add ClickHouse dialects.
2 Enable map access for function.

* 1 Fixed compilation errors.
2 Modify the code according to @alamb's comments.

* Fixed compilation errors.
2021-12-21 16:16:30 -05:00
Zach Hamlin
9569d1b215
feat: comment and alter column support (#381)
* feat: add support for postgresql comment keyword

* feat: add alter column and rename constraint
2021-12-17 12:19:08 -05:00
Taehoon Moon
823635d2fc
Add FunctionArgExpr and remove Expr::[Qualified]Wildcard, (#378)
* Add FunctionArgExpr and remove Expr::[Qualified]Wildcard,

There is no use case of `Expr::Wildcard` and `Expr::QualifiedWildcard` only except for function argments.
Add `FunctionArgExpr` to have `Wildcard` and `QualifiedWildcard`, and remove wildcards in `Expr`.

* Apply `FunctionArgExpr` to sqlparser_mysql tests
2021-12-15 06:35:37 -05:00
Poonai
4c121a92a6
support for session transaction and transaction snapshot. (#379)
* add support for snapshot id in set transaction

Signed-off-by: poonai <rbalajis25@gmail.com>

* add support for default session transaction characteristics

Signed-off-by: poonai <rbalajis25@gmail.com>

* add additional assertion for parse_set_transaction test

Signed-off-by: poonai <rbalajis25@gmail.com>

* Fix clippy

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-12-14 15:13:12 -05:00
Andrew Lamb
a81805ea30
Update to 0.13.1 alpha (#377)
I think I messed up cargo release, which has previously done this automatically
2021-12-11 07:15:07 -05:00
Andrew Lamb
e3269c158d (cargo-release) version 0.13.0 2021-12-10 15:00:47 -05:00
Andrew Lamb
a954f2de90 Update pre-commit version 2021-12-10 15:00:35 -05:00
Andrew Lamb
adaaab35e3
Update changelog for version 0.13.0 (#376) 2021-12-10 14:56:26 -05:00
Andrew Lamb
82eaae1522
Implement some MySQL specific syntax and extend the UPDATE statement (#375)
* * implement the ON DUPLICATE KEY syntax for MySQL in an INSERT statement

* * add MySQL to the cli example
* remove the dialect check for the ON DUPLICATE KEY insert to support
  custom dialects and unwrap some missing results

* * use the Assignment DataType for the ON DUPLICATE KEY UPDATE

* * add support for table aliases in an UPDATE statement
* add support for JOINS in an UPDATE statement (for MySQL)

* * implement the MySQL ALTER TABLE CHANGE COLUMN syntax

* * fix the formatting of the else * rename the parse_identifiers_strict
  to parse_identifiers_non_keywords

* Parse SUBSTRING calls that are separated with a comma instead of
keywords

* Fix the linting errors

Co-authored-by: Piotr <piotr.morawski@nc-vision.com>
Co-authored-by: Piotr Morawski <contact@peter-morawski.de>
2021-12-10 14:46:11 -05:00
Jiayu Liu
40d67aab87
parse grouping sets, rollup, and cube for postgresql (#366)
* parse grouping sets, rollup, and cube

* add postgresql flag
2021-12-10 14:45:09 -05:00
Ben Cook
d7e84be3e1
Add basic support for GRANT and REVOKE (#365)
* Add basic support for GRANT privileges on tables and sequences

* Cargo fmt

* Make enum for granted privileges

* Implement and use Display for GrantObjects

* Simplify Display for GrantPrivileges

* Add column privileges

* Add second column privilege to test

* Add REVOKE privileges and reformat

* Fix some clippy warnings

* Fix more clippy

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-12-08 15:55:23 -05:00
Jiayu Liu
d33bacf679
use 2021 edition (#368)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-12-08 15:44:20 -05:00
Andrew Lamb
41997b5750
Fix one last clippy warning (#374) 2021-12-08 15:41:07 -05:00
Jiayu Liu
0e1027ce96
fix clippy warnings (#367) 2021-12-08 08:27:00 +01:00
Heres, Daniel
9c87d3b195 Update release docs for new cargo release version 2021-10-14 18:35:36 +02:00
Heres, Daniel
a1937719b3 Update release notes 2021-10-14 18:32:23 +02:00
Daniël Heres
0f0b327e97
Implement is [not] distinct from (#361)
* Implement is [not] distinct from

* Simplify message

* Clippy
2021-10-14 18:26:28 +02:00
Qinxuan Chen
c9f8a44b55
Move the keywords module (#352)
* Move the keywords mod from dialect mod into the root of library

Signed-off-by: koushiro <koushiro.cqx@gmail.com>

* re-export keywords from dialect for backwards compatiblity

Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-09-26 07:59:39 -04:00
Andrew Lamb
3dd89ac44d (cargo-release) start next development iteration 0.11.1-alpha.0 2021-09-25 14:49:54 -04:00
Andrew Lamb
c2f9cfd2f0 (cargo-release) version 0.11.0 2021-09-25 14:49:54 -04:00
Andrew Lamb
8c39cec24c
Add release notes for 0.11.0 (#360) 2021-09-25 14:46:07 -04:00
Guillaume Balaine
d498887a5d
Enable map access for numbers, multiple nesting levels (#356)
* enable integer keys for map access

* enable map access for number keys

* Add tests for string based map access

* MapAccess: unbox single quoted strings to always display double quoted strings for map access

* cargo fmt

* cargo clippy

* Fix compilation with nostd by avoiding format!

* fix codestyle

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-09-24 14:22:12 -04:00
John
014b82f03d
Add logical xor (#357) 2021-09-18 06:39:35 -04:00
Qinxuan Chen
a8901becc3
Rname Token::Mult to Token::Mul (#353)
Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-09-16 16:50:10 -04:00
Hoon Wee
e32b1c56c8
Add gluesql as a reference (#355) 2021-09-16 07:34:18 +02:00
Qinxuan Chen
3d6637c4f3
Improve tokenizer error (#347)
* Improve tokenizer error

Signed-off-by: koushiro <koushiro.cqx@gmail.com>

* Add test for TokenizerError

Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-09-10 11:33:13 -04:00
Qinxuan Chen
10ec257e21
Use derive(Default) for HiveFormat (#348)
Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-09-09 12:24:17 -04:00
Dmitry Patsura
d2d4fc0c58
feat: Support DESCRIBE table_name (#340)
* feat: Support DESCRIBE

* feat: Support DESCRIBE table_name

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

* Update src/ast/mod.rs

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-09-09 11:49:33 -04:00
Qinxuan Chen
d8adb1708c
Eliminate redundant string copy of Tokenizer (#343)
Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-09-02 09:20:31 +02:00
Alex Vasilev
77d90d3b85
Support minimum display width for integer data types (#337)
* Support minimum display width for integers

* make fmt happy, updated docstrings
2021-08-29 07:13:10 -04:00
Dmitry Patsura
9a5716d94b
feat: Support SHOW CREATE TABLE|EVENT|FUNCTION (MySQL specific) (#338)
* feat: Support SHOW CREATE TABLE|EVENT|FUNCTION (MySQL specific)

* misc: Simplify test with loop over enum values
2021-08-29 07:03:39 -04:00
dependabot[bot]
69af5a1d99
Update bigdecimal requirement from 0.2 to 0.3 (#341)
Updates the requirements on [bigdecimal](https://github.com/akubera/bigdecimal-rs) to permit the latest version.
- [Release notes](https://github.com/akubera/bigdecimal-rs/releases)
- [Commits](https://github.com/akubera/bigdecimal-rs/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: bigdecimal
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-27 12:29:55 +02:00
TheSchemm
70ffa4166c
Support Parsing of hexadecimal literals that start with 0x (#324)
* Add support for 0x prefixed bin literal

* Add tests

* Fix formatting for test
2021-08-25 12:57:32 -04:00
joshwd36
a95c81fb13
Add referential actions to TableConstraint foreign key (#306)
* Add referential actions to TableConstraint foreign key

* Remove copy/paste error

* Add referential actions to TableConstraint foreign key

* Add additional tests
2021-08-25 12:03:10 -04:00
Andrew Lamb
f56e57470e (cargo-release) start next development iteration 0.10.1-alpha.0 2021-08-23 15:47:06 -04:00
Andrew Lamb
4d5aaa79b9 (cargo-release) version 0.10.0 2021-08-23 15:47:06 -04:00
Andrew Lamb
7e7d870e78
Add release notes for 0.10.0 (#336)
* Add release notes for 0.10.0

* Add mention of TRIM syntax
2021-08-23 15:42:01 -04:00
Jiseok CHOI
af1ac865b1
Add TrimWhereField for parse_trim_expr (#334)
* Remove Box from `trim_where`

* Add TrimWhereField for `parse_trim_expr`

* Add negative test case
2021-08-23 10:51:36 -04:00
Hoon Wee
5ce67177b3
Fix the term 'Modulus' to 'Modulo' (#335) 2021-08-23 12:05:42 +02:00
Andrew Lamb
31549b9241
Merge pull request #333 from andygrove/update-cargo-toml
Update links to reflect repository move to sqlparser-rs GitHub org
2021-08-23 06:01:32 -04:00
Andrew Lamb
2d04266a8e
Merge pull request #312 from PsiACE/main
Add fuzzer based on honggfuzz
2021-08-23 05:59:45 -04:00
Andy Grove
9c9d9293b5 fix typo 2021-08-21 06:54:49 -06:00
Qinxuan Chen
5bc109a7ad
Support no_std (#332)
* Support `no_std`

Signed-off-by: koushiro <koushiro.cqx@gmail.com>

* Fix typo

Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-08-21 10:15:43 +02:00
Andy Grove
3e34392230 Update links to reflect repository move to sqlparser-rs GitHub org 2021-08-20 17:05:02 -06:00
Andy Grove
5ebc06b20c Update links to reflect repository move to sqlparser-rs GitHub org 2021-08-20 17:03:06 -06:00
Andrew Lamb
293133f910
Merge pull request #313 from Jimexist/add-default-for-window-frame
add default value for window frame
2021-08-20 14:11:11 -04:00
Jiayu Liu
950daf39bb add default value for window frame 2021-08-20 13:55:53 -04:00
Andrew Lamb
783bc21d29
Merge pull request #328 from b41sh/regexp_match
Add support for PostgreSQL regex match
2021-08-20 13:54:24 -04:00
Jiseok CHOI
e548d38de8
Support TRIM syntax (#331)
* Support TRIM syntax

- Implement the following cases
- TRIM([BOTH | LEADING | TRAILING] <expr> [FROM <expr>])
- TRIM(<expr>)

* Resolve 1.54.0 clippy error

- Remove needless borrow

* Add test cases for TRIM
2021-08-20 08:53:52 +02:00
Qinxuan Chen
67e17b27f5
Make clippy happy (#330)
Signed-off-by: koushiro <koushiro.cqx@gmail.com>
2021-08-19 23:02:15 +02:00
b41sh
d312837d7a fmt 2021-08-18 22:40:40 +08:00
baishen
3c3bc3e97e
Update src/tokenizer.rs
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
2021-08-18 09:38:46 -05:00
baishen
24ca90acce
Merge pull request #1 from alamb/alamb/fixup_clippy
Fix clippy in regexp_match branch
2021-08-18 09:34:29 -05:00
Andrew Lamb
b6df67802f cargo fmt 2021-08-18 09:27:09 -04:00
b41sh
2c296f9dc4 fix clippy 2021-08-18 13:17:07 +08:00
b41sh
80759a4deb support regex match 2021-08-13 19:50:14 +08:00
sundyli
e5991f3ae5
Support tinyint (#320)
* Support tinyint

* Add tests
2021-07-17 14:16:38 +02:00
Andrew Lamb
c5de1225e9
Update datafusion link in README (#319) 2021-06-30 07:50:09 +02:00
Chojan Shang
a12dd0e83a *: make clippy happy
Signed-off-by: Chojan Shang <psiace@outlook.com>
2021-06-25 03:43:11 +08:00
Daniël Heres
d8775e2815
Fix linting errors (#318)
* Fix linting error

* Fix linting errors
2021-06-22 07:49:25 +02:00
BohuTANG
56e50dccd4
[parser] Return error instead of panic (#316)
* [parser] return error instead of panic

* Fix clippy warning

* Fix cargo fmt warning
2021-06-22 07:05:43 +02:00
Chojan Shang
0c52491191 docs: fuzzing
Signed-off-by: Chojan Shang <psiace@outlook.com>
2021-06-03 14:10:15 +08:00
Chojan Shang
1e65984613 test: add fuzzer
Signed-off-by: Chojan Shang <psiace@outlook.com>
2021-06-03 14:00:16 +08:00
Max Countryman
35ef0eee38
Merge pull request #300 from maxcountryman/feature/ilike
provide ILIKE support
2021-03-22 07:46:12 -07:00
Max Countryman
a9e6f77d62 provide ILIKE support
This introduces support for ILIKE and NOT ILIKE. ILIKE is the
case-insensitive variant of LIKE. Systems such as Postgres, Redshift,
and Snowflake provide this variant.[1][2][3]

[1] https://www.postgresql.org/docs/7.3/functions-matching.html
[2] https://docs.aws.amazon.com/redshift/latest/dg/r_patternmatching_condition_like.html
[3] https://docs.snowflake.com/en/sql-reference/functions/ilike.html
2021-03-22 07:31:42 -07:00
Heres, Daniel
1e87ab8e22 (cargo-release) start next development iteration 0.9.1-alpha.0 2021-03-21 23:29:18 +01:00
Heres, Daniel
f52891d0da (cargo-release) version 0.9.0 2021-03-21 23:29:18 +01:00
Heres, Daniel
c2340d1821 Add release notes for 0.8.0 2021-03-21 23:28:22 +01:00
Mike Seddon
e6e37b47db
Implement TRY_CAST (#299)
Adds support for `TRY_CAST` and fixes a clippy error
2021-03-21 23:26:16 +01:00
Heres, Daniel
43fef23bc8 (cargo-release) start next development iteration 0.8.1-alpha.0 2021-02-09 21:31:27 +01:00
Heres, Daniel
34cd794cd3 (cargo-release) version 0.8.0 2021-02-09 21:31:27 +01:00
Heres, Daniel
a868ff6ebe Add release notes 2021-02-09 21:30:05 +01:00
zhangli-pear
add8991144
feat: support sqlite insert or statement (#281) 2021-02-09 21:04:54 +01:00
Francis Du
07342d5853
Support parsing multiple show variables. (#290)
* feat: support parsing multiple show variables.

* fix: fix fmt error
2021-02-09 21:03:49 +01:00
Daniël Heres
f40955ee82
Parse floats without leading number (#294)
* Parse floats without leading number

* Move period token test

* Comments

* Enable test
2021-02-08 08:11:01 +01:00
Daniël Heres
6f0b2dcd92
Implement SUBSTRING(col [FROM <expr>] [FOR <expr>]) syntax (#293) 2021-02-07 08:06:50 -07:00
Stephen Carman
8a214f9919
Implement Hive QL Parsing (#235) 2021-02-04 12:53:20 -07:00
joshwd36
17f8eb9c5a
Fix clippy lints (#287) 2021-01-07 18:30:12 +01:00
Heres, Daniel
200ed5ecfc (cargo-release) start next development iteration 0.7.1-alpha.0 2020-12-28 21:51:28 +01:00
Heres, Daniel
e11b80ecf9 (cargo-release) version 0.7.0 2020-12-28 21:51:28 +01:00
Heres, Daniel
97cd1c017d Release 0.7.0 instead 2020-12-28 21:48:07 +01:00
Heres, Daniel
9930bdff68 (cargo-release) start next development iteration 0.6.3-alpha.0 2020-12-28 20:35:22 +01:00
Heres, Daniel
26c281eaf7 (cargo-release) version 0.6.2 2020-12-28 20:35:21 +01:00
Heres, Daniel
d66294fab8 Add date 2020-12-28 20:32:11 +01:00
Heres, Daniel
e18e8dc674 Prepare 0.6.2 2020-12-28 20:31:14 +01:00
Daniël Heres
94ff46802c
Support ANALYZE TABLE syntax (#285)
* Support analyze table

* Cleanup
2020-12-28 10:08:32 -07:00
Dmitry Patsura
17f2930885
Introduce support for EXPLAIN [ANALYZE] [VERBOSE] <STATEMENT> syntax
Introduce support for EXPLAIN [ANALYZE] [VERBOSE] <STATEMENT> syntax
2020-12-28 12:22:03 +01:00
Nickolay Ponomarev
cbd3c6b1a1
Merge pull request #263 from ballista-compute/documentation/cargo-release-config
add a note about cargo release config
2020-10-13 10:03:51 +03:00
Nickolay Ponomarev
929fc6764f
Merge pull request #260 from eyalleshem/single_tables_in_parens
[snowflake] Support `FROM (table_name) alias`
2020-10-13 09:59:38 +03:00
Nickolay Ponomarev
ad72cda6b0 [snowflake] Support specifying an alias after FROM (table_factor)
Snowflake diverges from the standard and from most of the other
implementations by allowing extra parentheses not only around a join,
but around lone table names (e.g. `FROM (mytable [AS alias])`) and
around derived tables (e.g. `FROM ((SELECT ...)  [AS alias])`) as well.

Initially this was implemented in https://github.com/ballista-compute/sqlparser-rs/issues/154
by (ab)using `TableFactor::NestedJoin` to represent anything nested in
extra set of parens.

Afterwards we learned in https://github.com/ballista-compute/sqlparser-rs/issues/223
that in cases of such extraneous nesting Snowflake allows specifying the
alias both inside and outside parens, but not both - consider:

    FROM (table_factor AS inner_alias) AS outer_alias

We've considered implementing this by changing `TableFactor::NestedJoin`
to a `TableFactor::Nested { inner: TableWithJoins, alias:
Option<TableAlias> }`, but that seemed too generic, as no known dialect
supports duplicate aliases, as shown above, nor naming nested joins
`(foo NATURAL JOIN bar) alias`. So we decided on making a smaller change
(with no modifications to the AST), that is also more appropriate to the
contributors to the Snowflake dialect:


1) Revert #154 by rejecting `FROM (table or derived table)` in most dialects.

2) For `dialect_of!(self is SnowflakeDialect | GenericDialect)` parse
and strip the extraneous parentheses, e.g.

   `(mytable) AS alias` -> `(mytable AS alias)`


Co-authored-by: Eyal Leshem <eyal@satoricyber.com>
2020-10-13 09:51:02 +03:00
Nickolay Ponomarev
d9e044aabb Extend one_statement_parses_to to also test parsing canonical SQL
It was an omission of the original implementation.
2020-10-12 06:52:39 +03:00
Nickolay Ponomarev
4128dfe1db Introduce tests/test_utils/mod.rs and use it consistently
To share helper macros between various tests/* we added a new module
(tests/macros/mod.rs). This made the prologue to be used in tests quite
long and a little weird:
```
#[macro_use]
#[path = "macros/mod.rs"]
mod macros;
use sqlparser::test_utils::*;
```

This simplifies it to:
```
#[macro_use]
mod test_utils;
use test_utils::*;
```
- and switches all existing tests to the new prologue simultaneously...

...while fixing a few other inconsistencies and adding a few comments
about the way `test_utils` work.
2020-10-12 06:52:00 +03:00
rhanqtl
9f772f03b0
Add support for Recursive CTEs (#278)
i.e. `WITH RECURSIVE ... AS ( ... ) SELECT` - see https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#with-clause

Fixes #277
2020-10-11 09:43:51 +03:00
Nickolay Ponomarev
99fb633221 Move existing SF tests to sqlparser_snowflake.rs
Co-authored-by: Eyal Leshem <eyal@satoricyber.com>
2020-10-05 08:42:26 +03:00
Nickolay Ponomarev
54be3912a9 Update CHANGELOG 2020-10-05 04:32:46 +03:00
Nickolay Ponomarev
7dc5d4c35e Follow-up to #275: Bump simple_logger version in Cargo.toml
SimpleLogger is private in v1.6. Bumping its version in Cargo.toml makes
`git pull && carg test` use the new version in an existing checkout
(with an existing Cargo.lock file referencing the old version)
2020-10-05 04:32:46 +03:00
Alex Dukhno
1ac208307c
Support IF NOT EXISTS for CREATE SCHEMA (#276)
This is a Postgres-specific clause: https://www.postgresql.org/docs/12/sql-createschema.html

Also add a test for `DROP SCHEMA IF EXISTS schema_name`, which is already supported in the parser.
2020-10-02 17:35:20 +03:00
Alex Dukhno
926b03a31d
Add parsing for PostgreSQL math operators (#267) 2020-09-30 05:29:31 +03:00
Nickolay Ponomarev
0ac343a116 Don't publish on the push of any tag
The tags are named vX.Y, and we'll be 0.x for a while, so limiting the
publish-crate action to run v0 tags seems good enough to avoid
accidental publishes.
2020-09-27 23:36:41 +03:00
Nickolay Ponomarev
cc4f51fe10 Update releasing.md docs 2020-09-27 23:34:21 +03:00
Daniël Heres
2f71324c33
Fix deprecated way of initializing SimpleLogger (#275)
* Use builder pattern instead as suggested
2020-09-07 09:34:27 +02:00
Nickolay Ponomarev
cf7263c294 Fix typo in the README
Closes https://github.com/ballista-compute/sqlparser-rs/issues/269
2020-09-07 04:31:07 +03:00
Nickolay Ponomarev
01a2a6bd0c
Update CHANGELOG (#261) 2020-09-07 04:11:26 +03:00
eyalleshem
1c6077c0db
[snowflake] Support single line comments starting with '#' or '//' (#264)
Co-authored-by: Eyal Leshem <eyal@satoricyber.com>
2020-09-07 03:57:37 +03:00
dependabot[bot]
e9aa87fa2c
Update bigdecimal requirement from 0.1 to 0.2 (#268)
Updates the requirements on [bigdecimal](https://github.com/akubera/bigdecimal-rs) to permit the latest version.
- [Release notes](https://github.com/akubera/bigdecimal-rs/releases)
- [Commits](https://github.com/akubera/bigdecimal-rs/compare/v0.1.0...v0.2.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-02 13:47:55 +02:00
Daniël Heres
a5b752484e
Fix clippy linting error, use enumerate (#266) 2020-08-27 21:32:06 +02:00
Andy Grove
038ef985a7
Add Ballista to the README as a user of this crate (#262) 2020-08-27 19:42:34 +02:00
Max Countryman
fcf1eb1b67
add a note about cargo release config 2020-08-14 10:47:35 -07:00
Max Countryman
118a345790
Merge pull request #238 from maxcountryman/feature/gh-action-releases
automate crate publishing
2020-08-12 07:04:38 -07:00
eyalleshem
f500a42e99
Add snowflake dialect (#259) 2020-08-12 04:55:22 +03:00
Nickolay Ponomarev
2c6c295dd0
Refactor <column definition> parsing (#251) 2020-08-10 17:19:33 +03:00
Nickolay Ponomarev
66505ebf9e Don't fail parsing a column definition with unexpected tokens
Since PR https://github.com/ballista-compute/sqlparser-rs/pull/93
`parse_column_def` parses a set of column options in a loop, e.g. given:

```
                  _______ column_def _______
CREATE TABLE foo (bar INT NOT NULL DEFAULT 1, )
                          -------- ---------
                          option 1  option 2
````

it parses column options until it encounters one of the delimiter tokens

First when we only supported `CREATE TABLE`, the set of delimiters that
stopped the parsing used to be `Token::Comma | Token::RParen`.

Then we added support for `ALTER TABLE ADD COLUMN <column_def>`. Turns
out the parser started to bail if the statement ended with a semicolon,
while attempting to parse the semicolon as a column option, as we forgot
to add it to the set of delimiter tokens.

This was recently fixed in https://github.com/ballista-compute/sqlparser-rs/pull/246
by including Token::SemiColon to the list, but it felt wrong to have
to update this list, and to have a common list of delimiters for two
different contexts (CREATE TABLE with parens vs ALTER TABLE ADD COLUMN
without parens).

Also our current approach cannot handle multiple statements NOT
separated by a semicolon, as is common in MS SQL DDL. We don't
explicitly support it in `parse_statements`, but that's a use-case
like to keep in mind nevertheless.
2020-08-10 17:12:33 +03:00
Nickolay Ponomarev
23f5c7e7ce Move parse_column_def below parse_columns
...because in the section related to CREATE TABLE parsing, the callers
are defined above the callees.
2020-08-10 17:09:34 +03:00
eyalleshem
1b46e82eec
Enable dialect specific behaviours in the parser (#254)
* Change `Parser { ... }` to store the dialect used:
    `Parser<'a> { ... dialect: &'a dyn Dialect }`

    Thanks to @c7hm4r for the initial version of this submitted as
    part of https://github.com/ballista-compute/sqlparser-rs/pull/170

* Introduce `dialect_of!(parser is SQLiteDialect |  GenericDialect)` helper
    to branch on the dialect's type

* Use the new functionality to make `AUTO_INCREMENT` and `AUTOINCREMENT`
  parsing dialect-dependent.


Co-authored-by: Christoph Müller <pmzqxfmn@runbox.com>
Co-authored-by: Nickolay Ponomarev <asqueella@gmail.com>
2020-08-10 16:51:59 +03:00
Daniël Heres
3871bbc5ee
Enable dependabot for this repository (#256)
* Enable dependabot for this repository

* Remove duplication, add sqlparser_bench
2020-08-05 09:03:29 +02:00
Daniël Heres
5f3a40e772
Dependency updates (#255) 2020-08-05 09:12:13 +03:00
eyalleshem
61431b087d
Support TABLE functions in FROM (#253)
Support `TABLE(...)` syntax in `FROM`, for example:

    select * from TABLE(SOME_FUNCTION(some_arg))

The ANSI spec allows routine invocations (and some other kinds of expressions we don't currently support) inside TABLE:
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#PTF-derived-table
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#table-function-derived-table
2020-08-05 08:59:43 +03:00
Heres, Daniel
a246d5da9a Undo accidental commit 2020-08-04 22:45:26 +02:00
Daniël Heres
caeb046803
Enable dependabot for this repository 2020-08-04 22:44:13 +02:00
eyalleshem
1cc3bf4099
Support named arguments in function invocations (#250)
This commit supports functions with argument names.

the format is :
"Select some_function( a => exp, b => exp2 .. ) FROM table1
OR
"select * from table(function(a => exp)) f;"

see:
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#named-argument-assignment-token
or the motivating example from snowflake:
https://docs.snowflake.com/en/sql-reference/functions/flatten.html
2020-08-02 08:04:55 +03:00
Max Countryman
9351efb437 update release instructions 2020-08-01 07:30:41 -07:00
Max Countryman
580e4b1d64
Merge pull request #252 from ballista-compute/fixup/use-nightly-fmt
ensure we use nightly with fmt
2020-07-31 09:48:58 -07:00
Max Countryman
6b37c1642f fix typo 2020-07-31 09:34:51 -07:00
Max Countryman
1a70c6e1fe document initial release process 2020-07-31 09:18:34 -07:00
Max Countryman
cac3a8ec1e provide missing license header 2020-07-31 09:01:32 -07:00
Max Countryman
76a911b34e
ensure we use nightly with fmt 2020-07-31 08:56:59 -07:00
mz
9c1a5a781d
Don't fail parsing ALTER TABLE ADD COLUMN ending with a semicolon (#246)
This is a follow-up to https://github.com/ballista-compute/sqlparser-rs/pull/203
where ALTER TABLE ADD COLUMN support was initially implemented.

Fixes #233.
2020-07-31 18:10:53 +03:00
mz
f8feff4ef2
Add SQLite dialect (#248) 2020-07-31 15:09:54 +03:00
mz
4452f9bad1
Support specifying ASC/DESC in index columns (#249)
...by reusing `OrderByExpr` for `columns` in `Statement::CreateIndex`.

This supports SQLite's indexed-column syntax https://www.sqlite.org/syntax/indexed-column.html

MSSQL's (`ON <object> ( column [ ASC | DESC ] [ ,...n ] )`)
https://docs.microsoft.com/en-us/sql/t-sql/statements/create-index-transact-sql?view=sql-server-ver15

And most of PostgreSQL syntax (except for opclass):
`( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )`
https://www.postgresql.org/docs/12/sql-createindex.html
2020-07-30 15:37:58 +03:00
mz
9e7e30282e
Support identifiers quoted with backticks in the MySQL dialect (#247)
Per https://dev.mysql.com/doc/refman/8.0/en/identifiers.html
MySQL historically supports `identifiers quoted in backticks`
in addition to the ANSI "quoting style" (assuming ANSI_QUOTES mode).
2020-07-30 04:22:29 +03:00
Nickolay Ponomarev
1337820c06
Merge pull request #245 from nickolay/cleanups
Minor code cleanups
2020-07-29 02:13:16 +03:00
Nickolay Ponomarev
a6e30b3fad Fix typo in JSONFILE serialization
Closes https://github.com/ballista-compute/sqlparser-rs/issues/237
2020-07-29 02:08:17 +03:00
Nickolay Ponomarev
9a2d86dcb5 Change CREATE INDEX serialization to not end with a semicolon 2020-07-29 02:08:17 +03:00
Nickolay Ponomarev
9371652446 Fix "unused stmt" warning in tests, with default features 2020-07-29 02:08:17 +03:00
Nickolay Ponomarev
3e880b599a Use consistent style for Display impls 2020-07-29 02:08:17 +03:00
Nickolay Ponomarev
d0db8a224b Run cargo fmt 2020-07-28 23:36:13 +03:00
mz
09ca14fe8e
Support dialect-specific auto-increment column options for MySQL and SQLite (#234)
In MySQL it's AUTO_INCREMENT
(see https://dev.mysql.com/doc/refman/8.0/en/create-table.html)
and in SQLite it's AUTOINCREMENT.

We use `ColumnOption::DialectSpecific(Vec<Token>)` to avoid adding a new variant for each vendor-specific column option.
2020-07-28 23:34:21 +03:00
Steven
8020b2e5f0
Add Postgres-specific PREPARE, EXECUTE and DEALLOCATE (#243)
Adds top-statements PREPARE, EXECUTE and DEALLOCATE for Postgres-specific feature prepared statement.
2020-07-28 12:01:52 +03:00
Daniël Heres
d2e4340a32
Support create or replace view/table (#239)
* Support create or replace table

* Support create or replace view

* Simplify create or replace table parser

* Add tests for create or replace external table and materialized view

* Formatting

* Address review comments

* Create error if we didn't see a (external) table or (materialized) view afer create or replace
2020-07-27 21:59:08 +02:00
Max Countryman
bc9bfaeb84 automate crate publishing
This introduces a new section of the GitHub Actions workflow which will
publish the crate upon a new tag being pushed. Note that this requires a
new project secret, `CRATES_TOKEN`.
2020-07-25 08:05:34 -07:00
Dandandan
f053383c71 Release 0.6.1 2020-07-20 18:20:08 +02:00
Daniël Heres
3a42b69b89
Release 0.6.0 (#232) 2020-07-20 18:14:46 +02:00
Daniël Heres
583f22b929
Remove PostgreSQL version of assert (#229)
Remove PostgreSQL procedural assert statement. This also simplifies code somewhat.
2020-07-17 13:20:49 +02:00
Daniël Heres
c24b0e01db
Implement ASSERT statement (#226)
As supported by PostgreSQL and BigQuery (with some differences between them)
2020-07-16 17:28:03 +02:00
Daniël Heres
5cab18963e
Add TPCH reggression tests (#221)
* Add TPC-H reggression tests
2020-07-14 21:48:07 +02:00
Max Countryman
f3b9edca28
update travis badge to point to actions status (#219)
* update travis badge to point to actions status

It seems Travis is currently not updating as expected, likely as a side effect of the repo moving. If we're comfortable leaning on Actions, then we can switch out the badge here and plan to remove Travis entirely. Alternatively we could reconfigure Travis to work with the new repo name.

* Refer to correct branch

Co-authored-by: Dandandan <danielheres@gmail.com>
2020-07-05 14:32:01 +02:00
Max Countryman
8cc7702a8c
update branch references to main (#215)
* update branch references to `main`

* ensure we point to ballista-compute

* update a couple of links to point to ballista-compute
2020-07-02 21:31:54 +02:00
Andy Grove
2a6d5f2b61
update cargo manifest (#214) 2020-06-28 09:52:52 -06:00
mz
a53f1d26ef
Support SQLite CREATE VIRTUAL TABLE (#209)
`CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`

https://www.sqlite.org/lang_createvtab.html
2020-06-28 04:31:33 +03:00
mz
0c83e5d9e8
Support SQLite's WITHOUT ROWID in CREATE TABLE (#208)
Per https://sqlite.org/lang_createtable.html

Co-authored-by: mashuai <mashuai@bytedance.com>
2020-06-26 15:11:46 +03:00
Nickolay Ponomarev
0c82be5c3b Follow-up to the recent release (CHANGELOG and the bench crate) 2020-06-26 15:00:12 +03:00
Andy Grove
1946791302 (cargo-release) start next development iteration 0.5.2-alpha.0 2020-06-25 20:46:29 -06:00
Andy Grove
05f8992a2f (cargo-release) version 0.5.1 2020-06-25 20:46:18 -06:00
Daniël Heres
15d5f71646
Add CREATE TABLE AS support (#206)
We parse it as a regular `CREATE TABLE` statement
followed by an `AS <query>`, which is how BigQuery works:
https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_statement


ANSI SQL and PostgreSQL only support a plain list of columns
after the table name in a CTAS
    `CREATE TABLE t (a) AS SELECT a FROM foo`

We currently only allow specifying a full schema with data
types, or omitting it altogether.

https://www.postgresql.org/docs/12/sql-createtableas.html
https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#as-subquery-clause


Finally, when no schema is specified, we print empty parens after a
plain `CREATE TABLE t ();` as required by PostgreSQL, but skip them
in a CTAS: `CREATE TABLE t AS ...`. This affects serialization only,
the parser allows omitting the schema in a regular `CREATE TABLE` too
since the first release of the parser:
7d27abdfb4/src/sqlparser.rs (L325-L332)

Co-authored-by: Nickolay Ponomarev <asqueella@gmail.com>
2020-06-23 16:30:22 +03:00
Jovansonlee Cesar
26361fd854
Implement ALTER TABLE DROP COLUMN (#148)
This implements `DROP [ COLUMN ] [ IF EXISTS ] column_name [ CASCADE ]`
sub-command of `ALTER TABLE`, which is what PostgreSQL supports https://www.postgresql.org/docs/12/sql-altertable.html
(except for the RESTRICT option)

Co-authored-by: Nickolay Ponomarev <asqueella@gmail.com>
2020-06-16 23:39:52 +03:00
mz
faeb7d440a
Implement ALTER TABLE ADD COLUMN and RENAME (#203)
Based on sqlite grammar
https://www.sqlite.org/lang_altertable.html
2020-06-16 22:52:37 +03:00
Daniël Heres
fab6e28271
Output DataType capitalized (#202)
This makes it consistent with other output which also prints keywords capitalized.
2020-06-13 16:18:44 +03:00
Daniël Heres
b24dbe513c
Replace FromStr with normal parser function for FileFormat (#201)
The previous version accepted quoting file format keywords
(`STORED AS "TEXTFILE"`) and was inconsistent with the
way WindowFrameUnits was parsed.
2020-06-13 15:38:01 +03:00
Daniël Heres
68afa2a764
Make FileFormat case insensitive (#200) 2020-06-12 18:10:44 +03:00
Taehoon Moon
a0f076acda
Make the cli example print JSON (#197)
...via the new json_example feature - to make it easier to try out the parser without coding.
2020-06-12 16:38:59 +03:00
Daniël Heres
f4fbd9b6b3
Take slice as input for parse_keywords (#199) 2020-06-12 02:10:17 +03:00
Max Countryman
6cdd4a146d
Support general "typed string" literals (#187)
Fixes #168 by enabling `DATE` and other keywords to be used as
identifiers when not followed by a string literal.

A "typed string" is our term for generalized version of `DATE '...'`/`TIME '...'`/
`TIMESTAMP '...'` literals, represented as `TypedString { data_type, value }`
in the AST.

Unlike DATE/TIME/TIMESTAMP literals, this is a non-standard extension
supported by PostgreSQL at least.

This is a port of MaterializeInc/materialize#3146

Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
Co-authored-by: Nickolay Ponomarev <asqueella@gmail.com>
2020-06-12 00:04:43 +03:00
Daniël Heres
34548e890b
Change Word::keyword to a enum (#193)
This improves performance and paves the way to future API enhancements as discussed in the PR https://github.com/andygrove/sqlparser-rs/pull/193
2020-06-11 22:00:35 +03:00
Nickolay Ponomarev
0fe3a8ec39
Use Token::EOF instead of Option<Token> (#195)
This simplifies codes slightly, removing the need deal with the EOF case explicitly.

The clone kludge in `_ => self.expected("date/time field",
Token::Word(w.clone())))` will become unnecessary once we stop using
a separate match for the keywords, as suggested in
https://github.com/andygrove/sqlparser-rs/pull/193#issuecomment-641607194
2020-06-10 14:05:17 +03:00
Taehoon Moon
2f1015339a
Add serde support to AST structs and enums (#196)
Apply serde to AST structs and enums to be serializable/deserializable.
serde support is optional, can be activated by feature named "serde".
2020-06-10 12:53:52 +03:00
Nickolay Ponomarev
d9a7491d9a Various follow-ups to recent pushes
- Update CHANGELOG
- Update `.gitignore` for the build directory of the benchmark crate
- Remove src/lib from the recently added benchmark crate per
  https://github.com/andygrove/sqlparser-rs/pull/190#pullrequestreview-425835379
2020-06-10 09:40:42 +03:00
Max Countryman
846c52f450
Allow omitting units after INTERVAL (#184)
Alter INTERVAL to support postgres syntax

This patch updates our INTERVAL implementation such that the Postgres
and Redshfit variation of the syntax is supported: namely that 'leading
field' is optional.

Fixes #177.
2020-06-10 09:32:13 +03:00
Daniël Heres
d842f495db
Add line and column number to TokenizerError (#194)
Addresses https://github.com/andygrove/sqlparser-rs/issues/179 for tokenize errors
2020-06-10 09:15:44 +03:00
Nickolay Ponomarev
10b0b7f884
Update CHANGELOG (#192)
Also remove a comment with a trailing space, which rustfmt doesn't like
2020-06-07 20:43:44 +03:00
Daniël Heres
a42121de52
Use binary search to speed up matching keywords (#191) 2020-06-07 20:25:10 +03:00
Max Countryman
af54eb02b2
Rework github actions, add code coverage (#186)
This reworks our GitHub Actions workflow to include code coverage via
tarpaulin.

Fixes #164.
2020-06-07 20:15:31 +03:00
Daniël Heres
6e6fae73a0
Add benchmarks using cargo bench / criterion (#190) 2020-06-07 16:46:55 +03:00
Daniël Heres
d32df527e6
Accept &str in Parse::parse_sql (#182)
It is more generic to accept a `&str` than a `String` in an API,
and avoids having to convert a string to a `String` when not
needed, avoiding a copy.
2020-06-03 23:31:41 +03:00
Daniël Heres
b4699bd4a7
Support bitwise and, or, xor (#181)
Operator precedence is coming from:

https://cloud.google.com/bigquery/docs/reference/standard-sql/operators
2020-06-03 19:02:05 +03:00
Daniël Heres
00dc490f72
Support the string concat operator (#178)
The selected precedence is based on BigQuery documentation, where it is equal to `*` and `/`:

https://cloud.google.com/bigquery/docs/reference/standard-sql/operators
2020-06-02 21:24:30 +03:00
Max Countryman
5f3c1bda01
Provide LISTAGG implementation (#174)
This patch provides an initial implemenation of LISTAGG[1]. Notably this
implemenation deviates from ANSI SQL by allowing both WITHIN GROUP and
the delimiter to be optional. We do so because Redshift SQL works this
way and this approach is ultimately more flexible.

Fixes #169.

[1] https://modern-sql.com/feature/listagg
2020-05-30 18:50:17 +03:00
QP Hou
418b9631ce
add nulls first/last support to order by expression (#176)
Following `<sort specification list>` from the standard https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_10_10_sort_specification_list
2020-05-30 17:05:15 +03:00
Nickolay Ponomarev
c918ff042d
Merge pull request #173 from alex-dukhno/create-schema
Support `CREATE SCHEMA schema_name` and `DROP SCHEMA schema_name`.

Both ANSI SQL and Posgres define a number of options for the CREATE SCHEMA statement.
They also support including other CREATE statements as part of the schema definition,
rather than separate statements. This PR supports neither.
2020-05-28 21:05:34 +03:00
Alex Dukhno
91f769e460 added create and drop schema 2020-05-28 19:50:16 +03:00
Nickolay Ponomarev
b28dd82838
Merge pull request #172 from nickolay/pr/readme
documentation updates
2020-05-27 19:49:50 +03:00
Nickolay Ponomarev
1cf9e5ecef Update README: we support bits and pieces from other dialects too 2020-05-27 19:45:18 +03:00
Nickolay Ponomarev
a2f4996bdd Update README to point to SQL:2016, instead of 2011
This was discussed in #125, but we forgot to update the README at the time.
2020-05-27 19:45:18 +03:00
Nickolay Ponomarev
8d5eaf95b3 Update CHANGELOG 2020-05-27 19:44:59 +03:00
Christoph Müller
98f97d09db
Add support for "on delete cascade" column option (#170)
Specifically, `FOREIGN KEY REFERENCES <foreign_table> (<referred_columns>)`
can now be followed by `ON DELETE <referential_action>` and/or by
`ON UPDATE <referential_action>`.
2020-05-27 18:24:23 +03:00
Nickolay Ponomarev
789fcc8521
Merge pull request #167 from mashuai/add_index_support
Adds support for the most common forms of CREATE INDEX, and for DROP INDEX:

	CREATE [ UNIQUE ] INDEX [ IF NOT EXISTS ]
	    <index_name>
	    ON <table_name>
	    ( col_name [, ...] )

	DROP INDEX <index_name>
2020-05-27 05:13:06 +03:00
Nickolay Ponomarev
320d2f2d05 Update CHANGELOG.md and a fix last-minute review nit 2020-05-27 05:04:22 +03:00
mashuai
5aacc5ebcd add create index and drop index support 2020-05-27 09:27:57 +08:00
Nickolay Ponomarev
2644bc4ac7
Merge pull request #171 from nickolay/master
Fix GitHub CI failures.
2020-05-26 21:47:25 +03:00
Nickolay Ponomarev
8406a938d5 Port the changes made to travis configuration in #159 to GitHub workflows
This should fix the build failures due to unavailable components, e.g.

error: component 'rustfmt' for target 'x86_64-unknown-linux-gnu' is unavailable for download for channel nightly
Sometimes not all components are available in any given nightly.
2020-05-26 21:35:12 +03:00
Nickolay Ponomarev
f614481133
Merge pull request #165 from nickolay/pr/unterminated-string-literal
Report an error on unterminated string literals (and more)
2020-05-26 06:42:35 +03:00
Nickolay Ponomarev
7d60bfd866 Update CHANGELOG.md 2020-05-10 21:50:06 +03:00
Nickolay Ponomarev
327e6cd9f1 Report an error for unterminated string literals
...updated the TODOs regarding single-quoted literals parsing while at it.
2020-05-10 21:21:01 +03:00
Nickolay Ponomarev
40853fe412 Fix a recently implemented clippy lint
https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
"Import with single component use path such as `use cratename;`
is not necessary, and thus should be removed."
2020-05-10 21:16:25 +03:00
Alex Dukhno
5ad578e3e5
Implement CREATE TABLE IF NOT EXISTS (#163)
A non-standard feature supported at least by Postgres

https://www.postgresql.org/docs/12/sql-createtable.html
2020-04-21 16:28:02 +03:00
Nickolay Ponomarev
06865113d7 Update comments (follow-up to PR #158) 2020-04-20 05:43:57 +03:00
Nickolay Ponomarev
af852e78f6
Merge pull request #158 from mjibson/offset-rows
Add support for OFFSET without the ROWS keyword (a MySQL quirk, documented at https://dev.mysql.com/doc/refman/8.0/en/select.html)

Teach the parser to remember which variant it saw (ROWS/ROW/none).
2020-04-20 05:38:04 +03:00
Nickolay Ponomarev
5fe9060d4e
Merge pull request #162 from alex-dukhno/derive-defaul-for-generic-dialect
derive default for GenericDialect
2020-04-20 05:13:12 +03:00
Matt Jibson
c0b0b5924d Add support for OFFSET with the ROWS keyword
MySQL doesn't support the ROWS part of OFFSET. Teach the parser to
remember which variant it saw, including just ROW.
2020-04-19 20:06:08 -06:00
Nickolay Ponomarev
05a29212ff Update comments (follow-up to PR #155)
https://github.com/andygrove/sqlparser-rs/pull/155
2020-04-20 04:58:24 +03:00
Nickolay Ponomarev
33303b244f
Merge pull request #155 from eyalleshem/master
Accept non-standard `Select * from (a)` queries, where the table name is inside parentheses.
2020-04-20 04:57:12 +03:00
Nickolay Ponomarev
b9f1ff685a
Merge pull request #159 to fix Travis CI 2020-04-20 03:02:54 +03:00
Alex Dukhno
baacc956ea derive default for GenericDialect 2020-04-19 13:07:00 +03:00
Nickolay Ponomarev
dcc624c561 Make CI handle missing rustfmt in the nightly 2020-04-14 19:48:15 +03:00
Nickolay Ponomarev
4ce0eb11ae Fix a new clippy lint (.nth(0)) to unbreak CI
"iter.next() is equivalent to iter.nth(0), as they both consume the
next element, but is more readable."

https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
2020-04-14 17:09:48 +03:00
Eyal Leshem
3255fd3ea8 Add support to to table_name inside parenthesis 2020-04-12 20:31:09 +03:00
Alex Kyllo
172ba42001 Add support for MSSQL's SELECT TOP N syntax (#150)
Add support for MSSQL SELECT TOP (N) [PERCENT] [WITH TIES] syntax.
2020-01-12 23:20:48 -05:00
Nikhil Benesch
4cdd6e2f84
Merge pull request #143 from apparebit/quote-id-quote
Support quoted identifiers in AST as well
2019-10-20 00:20:44 -04:00
Robert Grimm
b1cbc55128
Turn type Ident into struct Ident
The Ident type was previously an alias for a String. Turn it into a full
fledged struct, so that the parser can preserve the distinction between
identifier value and quote style already made by the tokenizer's Word
structure.
2019-10-20 00:16:41 -04:00
Andy Grove
9b2287f14c
Merge pull request #142 from andygrove/github-action
Add Github Action
2019-10-17 20:50:46 -06:00
Andy Grove
a2613f9dd1 format 2019-10-17 20:41:49 -06:00
Andy Grove
0687d3aca8 stable rust 2019-10-17 20:38:22 -06:00
Andy Grove
7730e5762a use stable rust 2019-10-17 20:35:09 -06:00
Nickolay Ponomarev
8c88294966
Merge pull request #141 from andygrove/changelog-0.5.0
Update CHANGELOG.md for 0.5.0
2019-10-17 23:50:51 +03:00
Andy Grove
41eda23ede test 2019-10-17 04:26:00 -06:00
Andy Grove
60448382c2 experimenting with github actions 2019-10-17 04:21:49 -06:00
Andy Grove
9b49db35ff
Add github action 2019-10-17 04:12:11 -06:00
Nickolay Ponomarev
489f157f17
Update CHANGELOG.md for 0.5.0 2019-10-11 00:18:35 +03:00
Andy Grove
adeb3f1f52 version bump 2019-10-10 08:09:26 -06:00
Andy Grove
8757a33013 version bump 2019-10-10 08:08:22 -06:00
Nikhil Benesch
c7021ed145
Merge pull request #139 from gaffneyk/master
Allow semicolon after start transaction
2019-09-14 00:25:44 -04:00
gaffneyk
2bb38c9b27
Parse START TRANSACTION when followed by a semicolon
Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-09-13 22:54:21 -04:00
Nikhil Benesch
abf68c6af6
Merge pull request #138 from andygrove/fix-skew
Fix merge skew with number literals
2019-09-02 09:48:57 -04:00
Nikhil Benesch
b8fe800da5
Fix merge skew with number literals 2019-09-02 09:37:38 -04:00
Nikhil Benesch
e9c5567b04
Merge pull request #135 from andygrove/show-columns
Support MySQL `SHOW COLUMNS` statement
2019-09-02 07:40:57 -04:00
Nikhil Benesch
f4df34074c
Merge pull request #130 from andygrove/decimal
Don't lose precision when parsing decimal fractions
2019-09-02 07:40:31 -04:00
Nikhil Benesch
a0aca824e8
Optionally parse numbers into BigDecimals
With `--features bigdecimal`, parse numbers into BigDecimals instead of
leaving them as strings.
2019-09-01 13:21:49 -04:00
Nikhil Benesch
b5621c0fe8
Don't lose precision when parsing decimal fractions
The SQL standard requires that numeric literals with a decimal point,
like 1.23, are represented exactly, up to some precision. That means
that parsing these literals into f64s is invalid, as it is impossible
to represent many decimal numbers exactly in binary floating point (for
example, 0.3).

This commit parses all numeric literals into a new `Value` variant
`Number(String)`, removing the old `Long(u64)` and `Double(f64)`
variants. This is slightly less convenient for downstream consumers, but
far more flexible, as numbers that do not fit into a u64 and f64 are now
representable.
2019-09-01 13:21:30 -04:00
Nikhil Benesch
e1ded184f8
Support SHOW <var> and SET <var> 2019-09-01 13:20:37 -04:00
Nikhil Benesch
2bef9ec30a
Merge pull request #121 from andygrove/ci-fmt
Check that CI enforces rustfmt
2019-08-27 18:15:43 -04:00
Brandon W Maister
f64928e994
Support MySQL SHOW COLUMNS statement
Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-08-14 15:13:05 -04:00
Nikhil Benesch
35a20091ea
Merge pull request #134 from umanwizard/expect_keywords
add `expect_keywords` function
2019-08-13 16:00:38 -04:00
Brennan Vincent
41d4ea480f
Add and use expect_keywords function
The code for parsing chains of expected keywords is more readable with
this helper function.

Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-08-13 15:42:14 -04:00
Nikhil Benesch
070d0192bf
Add missing license header 2019-08-13 15:04:42 -04:00
Nikhil Benesch
bc97543df3
Actually check rustfmt in CI
The previous incantation was simply *never* running rustfmt in CI,
rather than only running rustfmt on the nightly build.
2019-08-13 15:03:00 -04:00
Nickolay Ponomarev
391a54b5a3
Merge pull request #131 from nickolay/pr/refactoring
Assorted code simplification and doc improvements
2019-07-11 02:19:43 +03:00
Nickolay Ponomarev
086ba1281c Amend WindowFrame docs
The note about WindowFrameBound::Following being only valid "in
WindowFrame::end_bound" was both

- confusing, as it was based on the ANSI SQL syntax the parser doesn't
  adhere to -- though it sounded like a promise about the AST one could
  expect to get from the parser
- and incomplete, as the reality is that the bounds validation the SQL
  engine might want to perform is more complex. For example Postgres
  documentation says <https://www.postgresql.org/docs/11/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS>:

> Restrictions are that frame_start cannot be UNBOUNDED FOLLOWING,
> frame_end cannot be UNBOUNDED PRECEDING, and the frame_end choice
> cannot appear earlier in the above list of frame_start and frame_end
> options than the frame_start choice does — for example RANGE BETWEEN
> CURRENT ROW AND offset PRECEDING is not allowed. But, for example,
> ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING is allowed, even though it
> would never select any rows.
2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
f31636d339 Simplify parse_window_frame
It used to consume the `RParen` closing the encompassing `OVER (`, even
when no window frame was parsed, which confused me a bit, even though
I wrote it initially.

After fixing that, I took the opportunity to reduce nesting and
duplication a bit.
2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
9314371d3b Remove parse_expr_list, as it's now trivial 2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
03efcf6fa6 Add parse_comma_separated to simplify the parser
To use the new helper effectively, a few related changes were required:

- Each of the parse_..._list functions (`parse_cte_list`,
  `parse_order_by_expr_list`, `parse_select_list`) was replaced with a
  version that parses a single element of the list (e.g. `parse_cte`),
  with their callers now using
  `self.parse_comma_separated(Parser::parse_<one_element>)?`

- `parse_with_options` now parses the WITH keyword and a separate
  `parse_sql_option` function (named after the struct it produces) was
  added to parse a single k=v option.

- `parse_list_of_ids` is gone, with the '.'-separated parsing moved to
  `parse_object_name`.


Custom comma-separated parsing is still used in:
- parse_transaction_modes (where the comma separator is optional)
- parse_columns (allows optional trailing comma, before the closing ')')
2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
f11d74a64d Update Statement::Drop doc comment 2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
64e7be0c68 Move ObjectName closer to Ident in mod.rs 2019-07-09 03:27:20 +03:00
Nickolay Ponomarev
ac8ba107e3 Simplify Display implementations introduced in #124 2019-07-09 01:38:49 +03:00
Nickolay Ponomarev
1b31f03732 Change write! to write_str for better rustfmt formatting 2019-07-09 01:38:49 +03:00
Nickolay Ponomarev
275e6b13c9
Merge pull request #129 from nickolay/pr/changelog
Add a changelog
2019-07-09 01:17:00 +03:00
Nickolay Ponomarev
7c153e1ab0 Add changelog 2019-07-06 03:47:24 +03:00
Nikhil Benesch
8cd64e7b94
Merge pull request #128 from andygrove/readme
README: update for recent improvements
2019-07-03 10:30:35 -04:00
Nikhil Benesch
4172b68319
README: update for recent improvements
Remove outdated bits that claim shoddy SQL support and code
structure--we're much better on those fronts now! Also add a few
paragraphs about the current state of SQL compliance, why it's hard to
say anything detailed about SQL compliance, and what our long-term goals
are.
2019-07-03 01:39:14 -04:00
Andy Grove
7a4eb505b3 (cargo-release) start next development iteration 0.4.0 2019-07-01 18:19:02 -06:00
Andy Grove
4f805d6c96 (cargo-release) version 0.4.0 2019-07-01 18:17:47 -06:00
Nikhil Benesch
ed76cd68f8
Merge pull request #124 from vemoo/impl-display
implement fmt::Display instead of ToString
2019-07-01 16:24:53 -04:00
Nickolay Ponomarev
b6538592da
Merge pull request #126 from nickolay/pr/renames-comments
Update comments after the renaming done in PR #105
2019-07-01 04:56:18 +03:00
Nickolay Ponomarev
7d4b488336 Update comments after the renaming done in PR #105 2019-07-01 04:45:08 +03:00
Bernardo
b2b159fed1 implement fmt::Display instead of ToString 2019-06-30 17:32:51 +02:00
Nikhil Benesch
cdba43682f
Merge pull request #123 from benesch/eq
Implement Eq alongside Hash
2019-06-25 17:45:12 -04:00
Jamie Brandon
add898c2bd
Implement Eq alongside Hash
It turns out implementing Hash alone is not very useful, as
std::collection::HashMap keys are required to implement both Hash and
Eq.

Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-06-25 14:14:28 -04:00
Nikhil Benesch
f7199ec99f
Merge pull request #122 from benesch/sqlprefix-missed
Remove "SQL" prefix from "SQLDateTimeField" struct
2019-06-25 14:13:26 -04:00
Nikhil Benesch
106c9f8efb
Remove "SQL" prefix from "SQLDateTimeField" struct
I realized a moment too late that I'd missed a type name in
when removing the "SQL" prefix from types in ac555d7e8. As far as I can
tell, this was the only oversight.
2019-06-25 13:24:31 -04:00
Nikhil Benesch
bafb20746f
Merge pull request #105 from benesch/renames
Remove "SQL" from types (and other renames)
2019-06-25 13:16:13 -04:00
Nikhil Benesch
ac555d7e86
Remove "SQL" prefix from types
The rationale here is the same as the last commit: since this crate
exclusively parses SQL, there's no need to restate that in every type
name. (The prefix seems to be an artifact of this crate's history as a
submodule of Datafusion, where it was useful to explicitly call out
which types were related to SQL parsing.)

This commit has the additional benefit of making all type names
consistent; over type we'd added some types which were not prefixed with
"SQL".
2019-06-25 13:11:11 -04:00
Nikhil Benesch
cf655ad1a6
Remove "sql" prefix from module names
Since this crate only deals with SQL parsing, the modules are understood
to refer to SQL and don't need to restate that explicitly.
2019-06-24 12:56:26 -04:00
Nikhil Benesch
5b23ad1d4c
Merge pull request #119 from andygrove/astnode-expr
Rename ASTNode to Expr
2019-06-19 21:45:49 -04:00
Nickolay Ponomarev
3c401d5e4f
Merge pull request #120 from nickolay/pr/outer-apply
[mssql/oracle] Support CROSS/OUTER APPLY
2019-06-19 13:26:35 +03:00
Nikhil Benesch
646d1e13ca
Rename ASTNode to Expr
The ASTNode enum was confusingly named. In the past, the name made
sense, as the enum contained nearly all of the nodes in the AST, but
over time, pieces have been split into different structs, like
SQLStatement and SQLQuery. The ASTNode enum now contains only contains
expression nodes, so Expr is a better name.

Also rename the UnnamedExpression and ExpressionWithAlias variants
of SQLSelectItem to UnnamedExpr and ExprWithAlias, respectively, to
match the new shorthand for the word "expression".
2019-06-19 00:00:59 -04:00
Nickolay Ponomarev
4294581ded [mssql] Parse CROSS/OUTER APPLY
T-SQL (and Oracle) support non-standard syntax, which is similar in
functionality to LATERAL joins in ANSI and PostgreSQL
<https://blog.jooq.org/tag/lateral-derived-table/>: it allows to use
the columns from the tables defined to the left of `APPLY` in the
"derived tables" (subqueries) to the right of `APPLY`. Unlike ANSI
LATERAL (but like Postgres' implementation), APPLY is also used with
table-valued function calls.

Despite them being similar, we represent "APPLY" joins with
`JoinOperator`s of its own (`CrossApply` and `OuterApply`). Doing
otherwise seemed like it would cause unnecessary confusion, as those
interested in dialect-specific parsing would probably not expect APPLY
being parsed as LATERAL, and those wanting to forbid non-standard SQL
would not be helped by this either.

This also renames existing JoinOperator::Cross -> CrossJoin to avoid
confusion with CrossApply.
2019-06-19 02:45:47 +03:00
Nickolay Ponomarev
0f6bf15258 Fix bad merge in #118 2019-06-19 02:45:47 +03:00
Nikhil Benesch
e6b26330df
Merge pull request #118 from andygrove/outer-join
Don't silently accept naked OUTER JOINS
2019-06-18 13:15:25 -04:00
Nikhil Benesch
2c99635709
Don't silently accept naked OUTER JOINS
`SELECT * FROM a OUTER JOIN b` was previously being parsed as an inner
join where table `a` was aliased to `OUTER`. This is extremely
surprising, as the user likely intended to say FULL OUTER JOIN. Since
the SQL specification lists OUTER as a keyword, we are well within our
rights to return an error here.
2019-06-18 12:03:15 -04:00
Nickolay Ponomarev
7857543749
Merge pull request #116 from nickolay/pr/more-followups
Support HAVING/LIMIT/OFFSET/FETCH without FROM and other follow-ups
2019-06-18 02:58:31 +03:00
Nickolay Ponomarev
a37ba089ec Add a comment about RESERVED_FOR_TABLE_ALIAS to parse_table_and_joins 2019-06-17 10:55:20 +03:00
Nickolay Ponomarev
eb3450dd51 Support HAVING without GROUP BY
...which is weird but allowed:
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#table-expression
https://dba.stackexchange.com/a/57453/15599

Also add a test for GROUP BY .. HAVING
2019-06-17 01:06:32 +03:00
Nickolay Ponomarev
d60bdc0b92 Allow LIMIT/OFFSET/FETCH without FROM
Postgres allows it, as does ANSI SQL per the <query expression> definition:
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#_7_13_query_expression
2019-06-17 00:54:37 +03:00
Nickolay Ponomarev
c1509b36ec Use FETCH_FIRST_TWO_ROWS_ONLY in tests to reduce duplication 2019-06-17 00:49:25 +03:00
Nickolay Ponomarev
f87e8d5158 Don't duplicate all the parse_simple_select assertions in the LIMIT test 2019-06-17 00:39:00 +03:00
Nickolay Ponomarev
3c073a4c34 Use TableAlias in Cte 2019-06-16 21:18:57 +03:00
Nickolay Ponomarev
4f239745bc Update comments now that get_precedence is no more 2019-06-16 21:01:29 +03:00
Nickolay Ponomarev
dc26c4abd5
Merge pull request #115 from nickolay/pr/followups
Doc improvements and follow-ups to the recent PRs
2019-06-15 01:57:52 +03:00
Nikhil Benesch
98a06d6d23
Merge pull request #111 from benesch/join-tweaks
Refine join parsing
2019-06-14 16:45:06 -04:00
Nickolay Ponomarev
535505bb96
Update the error message in parse_query_body 2019-06-14 16:28:53 -04:00
Nikhil Benesch
4ee461bae4
Require that nested joins always have one join
The SQL specification prohibits constructions like

    SELECT * FROM a NATURAL JOIN (b)

where b sits alone inside parentheses. Parentheses in a FROM entry
always introduce either a derived table or a join.
2019-06-14 16:28:52 -04:00
Nikhil Benesch
8bee74277a
Handle derived tables with set operations
This commit adds support for derived tables (i.e., subqueries) that
incorporate set operations, like:

    SELECT * FROM (((SELECT 1) UNION (SELECT 2)) t1 AS NATURAL JOIN t2)

This introduces a bit of complexity around determining whether a left
paren starts a subquery, starts a nested join, or belongs to an
already-started subquery. The details are explained in a comment within
the patch.
2019-06-14 16:28:52 -04:00
Nickolay Ponomarev
5c7ff79e78 Add a test for parsing the NULL literal
(Coveralls notices we didn't have one.)
2019-06-13 11:17:36 +03:00
Nickolay Ponomarev
45c9aa1cc2 Use self.expected() more 2019-06-13 11:15:10 +03:00
Nickolay Ponomarev
f18fbe5cda Remove unused parse_literal_double
`parse_value` handles parsing a non-integer value in expression context,
and we use parse_literal_uint() when expecting a number in other 
contexts (such as `FETCH FIRST ... ROWS`)
2019-06-13 11:11:23 +03:00
Nickolay Ponomarev
7041850b33 Reduce nesting in parse_table_and_joins
This is a follow-up to #109 which moved the handling of Token::Comma
from parse_table_and_joins to the `FROM` parser.
2019-06-13 04:30:14 +03:00
Nickolay Ponomarev
32cf36e64f Add a testcase, which passes thanks to PR #109 2019-06-12 21:04:31 +03:00
Nickolay Ponomarev
6b0a396785 Remove table_key.rs accidentally re-added in PR #79 2019-06-12 21:04:31 +03:00
Nickolay Ponomarev
cfb77912f7 Mention SQLSelectItem::Wildcard in ASTNode::SQLWildcard docs
as a follow-up to https://github.com/andygrove/sqlparser-rs/issues/52
2019-06-12 21:04:31 +03:00
Nickolay Ponomarev
846f2ff1d9 Fix intra_doc_link_resolution_failure in cargo doc
..and other formatting errors.
2019-06-12 21:04:27 +03:00
Nickolay Ponomarev
26fac099b1 Update Value docs 2019-06-12 21:04:23 +03:00
Andy Grove
1998910bfa
Merge pull request #113 from andygrove/revert-78-visitor
Revert "Add an AST visitor"
2019-06-10 21:56:42 -06:00
Andy Grove
b07c7a90f1
Revert "Add an AST visitor" 2019-06-10 21:51:10 -06:00
Andy Grove
7ed6e03880
Merge pull request #78 from benesch/visitor
Add an AST visitor
2019-06-10 21:19:45 -06:00
Nikhil Benesch
f2fda57e36
Merge pull request #112 from benesch/expr-consistency
Improve consistency of binary/unary op nodes
2019-06-10 23:08:33 -04:00
Nikhil Benesch
ae25dce246
Split operators by arity
It is useful downstream to have two separate enums, one for unary
operators and one for binary operators, so that the compiler can check
exhaustiveness. Otherwise downstream consumers need to manually encode
which operators are unary and which operators are binary when matching
on an Operator enum.
2019-06-10 23:03:11 -04:00
Nikhil Benesch
9e33cea9b8
Standardize BinaryOp and UnaryOp nodes
These were previously called "BinaryExpr" and "Unary"; besides being
inconsistent, it's also not correct to say "binary expression" or "unary
expression", as it's the operators that have arities, not the
expression. Adjust the naming of the variants accordingly.
2019-06-10 23:02:17 -04:00
Andy Grove
b379480b7a
Merge pull request #79 from benesch/license
Standardize license headers
2019-06-10 19:39:12 -06:00
Nikhil Benesch
5896f01ce0
Merge pull request #109 from benesch/implicit-join-fix
Properly handle mixed implicit and explicit joins
2019-06-10 11:17:01 -04:00
Nikhil Benesch
ce171c2a3d
Support VALUES and parenthesized SELECTs as top-level statements 2019-06-10 11:11:26 -04:00
Nikhil Benesch
b841dccc2c
Properly handle mixed implicit and explicit joins
Parse a query like

    SELECT * FROM a NATURAL JOIN b, c NATURAL JOIN d

as the SQL specification requires, i.e.:

    from: [
        TableReference {
            relation: TableFactor::Table("a"),
            joins: [Join {
                relation: TableFactor::Table("b"),
                join_operator: JoinOperator::Natural,
            }]
        },
        TableReference {
            relation: TableFactor::Table("c"),
            joins: [Join {
                relation: TableFactor::Table("d"),
                join_operator: JoinOperator::Natural,
            }]
        }
    ]

Previously we were parsing such queries as

    relation: TableFactor::Table("a"),
    joins: [
        Join {
            relation: TableFactor::Table("b"),
            join_operator: JoinOperator::Natural,
        },
        Join {
            relation: TableFactor::Table("c"),
            join_operator: JoinOperator::Implicit,
        },
        Join {
            relation: TableFactor::Table("d"),
            join_operator: JoinOperator::Natural,
        },
    ]

which did not make the join hierarchy clear.
2019-06-10 11:11:25 -04:00
Nickolay Ponomarev
518c8833d2
Merge pull request #110 from nickolay/pr/cleanups
Minor code clean-ups
2019-06-09 20:24:13 +03:00
Nikhil Benesch
2d1e05e21d
Merge pull request #103 from benesch/intervals
Support interval literals
2019-06-09 12:41:57 -04:00
Nikhil Benesch
2798ddf5fd
Support interval literals 2019-06-09 12:37:57 -04:00
Nickolay Ponomarev
99768711dc Fix redundant closures in tests
We don't have the tests checked by clippy on CI, despite [passing the
`--all-targets`](5536cd1f9e/.travis.yml (L46)),
but VSCode+RLS display warnings for these.

See: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
2019-06-09 17:05:19 +03:00
Nickolay Ponomarev
b6dac5099d Use the same pattern to parse comma-separated lists of things 2019-06-09 16:47:02 +03:00
Nickolay Ponomarev
ab88e02f0d Raise a TokenizerError when a delimited identifier is not closed before EOF 2019-06-09 16:42:23 +03:00
Nickolay Ponomarev
20637f0327 Introduce peeking_take_while to simplify tokenizer
I could probably look into using an existing crate like
https://github.com/fitzgen/peeking_take_while - but as a small helper
works as well I didn't have the reason to.
2019-06-09 16:42:23 +03:00
Nickolay Ponomarev
ebc5efda98 Reduce duplication in tokenizer by matching on Some('...') directly 2019-06-09 16:42:23 +03:00
Nikhil Benesch
5536cd1f9e
Merge pull request #106 from offscale/transactions
Transaction support
2019-06-09 01:35:05 -04:00
Nikhil Benesch
7e96d81b47
Merge pull request #93 from benesch/col-constr-order
Parse column constraints in any order
2019-06-09 00:36:51 -04:00
Agustin Chiappe Berrini
582b25add6
Add basic support for transaction statements
Co-authored-by: Samuel Marks <807580+SamuelMarks@users.noreply.github.com>
Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-06-09 00:36:20 -04:00
Nikhil Benesch
4a5099fdba
Merge pull request #108 from benesch/test-nesting
Test that redundant nesting is supported
2019-06-09 00:28:44 -04:00
Nikhil Benesch
ffa1c8f853
Parse column constraints in any order
CREATE TABLE t (a INT NOT NULL DEFAULT 1 PRIMARY KEY) is as valid as
CREATE TABLE t (a INT DEFAULT 1 PRIMARY KEY NOT NULL).
2019-06-08 12:13:55 -04:00
Nikhil Benesch
ccbd048dda
Test that redundant nesting is supported
SELECT * FROM (((SELECT 1))) is just as valid as
SELECT * FROM (SELECT 1). Add a test to ensure that we can parse the
first form.

Addresses a comment from #100.
2019-06-07 23:54:56 -04:00
Nikhil Benesch
5f9f17de8a
Merge pull request #100 from benesch/nested-joins
Support nested joins
2019-06-07 22:37:53 -04:00
Nikhil Benesch
fc5e662b91
Merge pull request #107 from benesch/prec
Fix precedence of unary NOT
2019-06-06 17:26:00 -04:00
Nikhil Benesch
525f4d7501
Fix precedence of unary NOT
get_next_precedence deals with left-binding power, not right binding
power. Therefore, when it encounters a standalone NOT operator (i.e., a
"NOT" token that is not followed by "BETWEEN", "LIKE", or "IN"), it
should return 0, because unary NOT is not an infix operator, it's a
prefix operator, and therefore it has no left-binding power.
2019-06-06 17:20:07 -04:00
Nikhil Benesch
ee49af3f52
Add an AST visitor 2019-06-05 14:06:45 -04:00
Nikhil Benesch
e78cf0483e
Standardize license headers
Standardize the license header, removing the Grove Enterprise copyright
notice where it exists per #58. Also add a CI check to ensure that files
without license headers don't get merged.

Fix #58.
2019-06-04 10:54:12 -04:00
Nikhil Benesch
8fbf82deb0
Support nested joins
Fix #83.
2019-06-04 10:25:07 -04:00
Nikhil Benesch
1f87083906
Merge pull request #99 from benesch/dates
Basic date/time support
2019-06-04 00:30:21 -04:00
Nikhil Benesch
ed3ed26bb1
Support parsing dates, times, and timestamps as strings 2019-06-04 00:12:09 -04:00
Nikhil Benesch
11fc833433
Merge pull request #96 from benesch/extract
Support EXTRACT function-like operator
2019-06-04 00:07:23 -04:00
Nikhil Benesch
4c2722280d
Merge pull request #98 from benesch/col-names
Support column names in more places
2019-06-04 00:00:07 -04:00
Nikhil Benesch
9abcac350e
Support aliasing columns
A table alias can specify new names for the columns within the aliased
table, in addition to a new name for the table itself.
2019-06-03 23:51:23 -04:00
Nikhil Benesch
73ed685879
Support views with explicit column names
A `CREATE VIEW` statement may provide names for its columns that
override the names of the columns derived from the view's query.
2019-06-03 23:50:23 -04:00
Nikhil Benesch
fdbf64c64d
Merge pull request #94 from benesch/empty-create-table
Support CREATE TABLE with no columns
2019-06-03 23:44:18 -04:00
Nikhil Benesch
d484756182
Support EXTRACT function-like operator
The EXTRACT function, for extracting components of a date from a
timestamp, has special syntax: `EXTRACT(<field> FROM <timestamp>)`.
2019-06-03 23:37:39 -04:00
Nikhil Benesch
2f4cd8f6c8
Merge pull request #102 from benesch/ci-speedup
Speed up CI
2019-06-03 23:34:39 -04:00
Nikhil Benesch
a594375966
Merge pull request #97 from benesch/update
Support UPDATE statements
2019-06-03 23:32:23 -04:00
Nikhil Benesch
610d6f8304
Improve CI caching
We weren't making very effective use of the cache before, leading to
10m+ builds, as `cargo install --force` always busts the cache.
2019-06-03 17:46:20 -04:00
Nikhil Benesch
e753bd4f90
Install kcov via APT
This prevents cargo coveralls from downloading it and compiling it on
the fly.
2019-06-03 17:36:35 -04:00
Nikhil Benesch
b7125c979a
Upgrade CI to Xenial
This isn't required by anything, but newer distributions tend to boot
faster in Travis.
2019-06-03 17:33:44 -04:00
Nikhil Benesch
6fceba8aa1
Merge pull request #74 from benesch/with-options
Support arbitrary WITH options for CREATE [TABLE|VIEW]
2019-06-03 13:57:38 -04:00
Nikhil Benesch
69f0082db6
Support arbitrary WITH options for CREATE [TABLE|VIEW]
Both Postgres and MSSQL accept this syntax, though the particular
options they accept differ.
2019-06-03 13:32:13 -04:00
Nikhil Benesch
1931c76eb8
Merge pull request #101 from benesch/merge-skew
Fix merge skew by implementing Hash for SQLValues
2019-06-03 12:28:49 -04:00
Nikhil Benesch
fa3cf732d5
Fix merge skew by implementing Hash for SQLValues 2019-06-03 12:08:06 -04:00
Nikhil Benesch
b12fb34f3d
Merge pull request #95 from benesch/hex-literals
Support hexadecimal string literals
2019-06-03 11:49:25 -04:00
Nikhil Benesch
b8ba188191
Merge pull request #91 from benesch/from-values
Improve VALUES-related syntax parsing
2019-06-03 11:44:52 -04:00
Nikhil Benesch
eba3983268
Support hexadecimal string literals 2019-06-03 11:33:51 -04:00
Nikhil Benesch
057518b377
Merge pull request #88 from benesch/hash
Implement Hash on all AST nodes
2019-06-03 11:29:31 -04:00
Nikhil Benesch
7aff70772b
Merge pull request #90 from benesch/exists
Support EXISTS subqueries
2019-06-03 11:29:04 -04:00
Nikhil Benesch
14e07ebdda
Support arbitrary INSERT sources
INSERT takes arbitrary queries as sources, not just VALUES clauses. For
example, `INSERT INTO foo SELECT * FROM bar` is perfectly valid.
2019-06-03 11:27:21 -04:00
Nikhil Benesch
9420070a0d
Support VALUES clauses in FROM
VALUES clauses are not just valid in INSERT statements. They're also
valid (basically) anywhere table expressions are accepted, like in FROM
clauses.
2019-06-03 11:26:45 -04:00
Nikhil Benesch
975106b207
Support EXISTS subqueries
Fix #5.
2019-06-03 11:14:24 -04:00
Nikhil Benesch
c49352f394
Implement Hash on all AST nodes
It is convenient for downstream libraries to be able to stash bits of
ASTs into hash maps, e.g., for performing simple common subexpression
elimination.

The only downside to this change is that it requires that the f64 in the
Value enum be wrapped in an OrderedFloat, which provides the necessary
equality semantics to allow Hash to be drived. The reason f64 doesn't
implement Hash by default is because NaN is typically not equal to
itself, so it's not clear what it should hash to. That's less of a
concern in a SQL context, because every SQL database I've looked at
treats NaN as equal to itself, in violation of the IEEE standard, in
order to permit indexing and sorting of float columns.
2019-06-03 11:11:24 -04:00
Nikhil Benesch
a3aaa49a7e
Merge pull request #89 from benesch/sqlfunction-struct
Extract a SQLFunction struct
2019-06-03 11:09:27 -04:00
Nikhil Benesch
1ddef7aa71
Merge pull request #92 from benesch/decimal-dec
Parse DECIMAL and DEC aliases for NUMERIC type
2019-06-03 11:08:18 -04:00
Nikhil Benesch
85ba953ea1
Merge pull request #87 from nickolay/pr/join-refactor
Refactor parse_joins
2019-06-03 00:55:23 -04:00
Nikhil Benesch
1cef68e510
Support UPDATE statements
Fix #10.
2019-06-03 00:21:23 -04:00
Nikhil Benesch
b3a2a6be48
Support CREATE TABLE with no columns
This is weird, but supported by PostgreSQL.
2019-06-02 23:50:16 -04:00
Nikhil Benesch
054a59df12
Extract a SQLFunction struct
This variant is getting rather large, and it's useful downstream to be
able to pass around SQLFunction nodes without reinventing the wheel.
2019-06-02 23:00:28 -04:00
Nikhil Benesch
38fc920d7c
Parse DECIMAL and DEC aliases for NUMERIC type 2019-06-02 22:40:18 -04:00
Nickolay Ponomarev
d0f2de06ed Refactor parse_joins, pt.2: implicit/cross/natural joins
- reduce duplication in the handling of implicit/cross joins and make
  the flow of data slightly clearer by returning the `join` instead of
  pushing it and exiting early.

  (I wanted the block that currently returns `join` to return one of
  JoinOperator::* tags, so that `parse_table_factor` and the construction
  of the `Join` struct could happen after we've parsed the JOIN keywords,
  but that seems impossible.)

- move the check for the NATURAL keyword into the block that deals with 
  INNER/OUTER joins that support constraints (and thus can be preceded
  by "NATURAL")

- add a check for NATURAL not followed by a known join type with a test

- add more tests for NATURAL joins (we didn't have any), and fix
  whitespace bug in `to_string()` that was uncovered (we emitted an
  extra space: `foo NATURAL JOIN bar `)
2019-06-03 02:44:03 +03:00
Nickolay Ponomarev
665b9df729 Refactor parse_joins, pt.1: INNER/OUTER joins
This block parses one of:
- `[ INNER ] JOIN <table_factor> <join_constraint>`
- `{ LEFT | RIGHT | FULL } [ OUTER ] JOIN <table_factor> <join_constraint>`

..but it was hard to see because of the duplication.
2019-06-03 02:44:03 +03:00
Nickolay Ponomarev
8206523416 Minor consume_token()-related simplifications
- use `if !self.consume_token(&Token::Comma) { break; }` to consume the
  comma and exit the loop if no comma found.
- coalesce two `{ false }` blocks in `consume_token` by using a match guard
2019-06-03 02:44:03 +03:00
Nickolay Ponomarev
2308c1c6f7
Merge pull request #86 from nickolay/pr/token-refactor
Internal improvements to Parser::next_token/prev_token

This reduces the number of helper functions used by next_token()/prev_token() while slightly improving performance and reducing the chances of coding errors when using prev_token() after hitting end-of-file.
2019-06-03 02:42:59 +03:00
Nickolay Ponomarev
e02625719e Allow calling prev_token() after EOF
Before this `next_token()` would only increment the index when returning
`Some(token)`. This means that the caller wishing to rewind must be
careful not to call `prev_token()` on EOF (`None`), while not forgetting
to call it for `Some`. Not doing this resulted in bugs in the
undertested code that does error handling.

After making this mistake several times, I'm changing `next_token()` /
`prev_token()` so that calling `next_token(); prev_token(); next_token()`
returns the same token in the first and the last invocation.
2019-06-02 22:57:44 +03:00
Nickolay Ponomarev
1227fddd48 Reduce cloning of tokens
- Avoid cloning whitespace tokens in `peek_nth_token()` by using a
  &Token from `tokens.get()` instead of a cloned `Token` from `token_at()`

- Similarly avoid cloning in `next_token_no_skip`, and clone the
  non-whitespace tokens in `next_token` instead.

- Remove `token_at`, which was only used in `peek_token` and
  `peek_nth_token`

- Fold `prev_token_no_skip()` into `prev_token()` and make `prev_token`
  return nothing, as the return value isn't used anyway.
2019-06-02 22:57:44 +03:00
Nickolay Ponomarev
ebb82b8c8f
Merge pull request #65 from nickolay/pr/ddl-improvements
* Rewrite parsing of `ALTER TABLE ADD CONSTRAINT`
* Support constraints in CREATE TABLE
* Change `Value::Long()` to be unsigned, use u64 consistently
* Allow trailing comma in CREATE TABLE
2019-06-02 20:53:21 +03:00
Nikhil Benesch
5847a16fff
Merge pull request #85 from benesch/clippy
Enable Clippy and rustfmt in CI
2019-06-02 10:51:28 -04:00
Nikhil Benesch
1cc9d2d6f5
Merge pull request #82 from benesch/not-prec
Fix the precedence of NOT LIKE
2019-06-02 10:49:49 -04:00
Nickolay Ponomarev
58420cab61
Merge pull request #66 from nickolay/pr/ms-identifiers-aliases
Support for MSSQL identifier and alias parsing rules
2019-06-02 14:19:51 +03:00
Nickolay Ponomarev
d9edc2588b Change Value::Long() to u64, use u64 instead of usize
The tokenizer emits a separate Token for +/- signs, so the value of
Value::Long() (as well as of parse_literal_int()) may never be negative.

Also we have been using both u64 and usize to represent a parsed
unsigned number. Change to using u64 for consistency.
2019-06-02 13:58:14 +03:00
Nickolay Ponomarev
0407ed2b57 Allow trailing comma in CREATE TABLE
At least MSSQL supports it, not sure about others.
2019-06-02 13:54:16 +03:00
Nickolay Ponomarev
8569a61fd0 Rename AlterOperation -> AlterTableOperation
Since other ALTER statements will have separate sub-commands.
2019-06-02 13:54:16 +03:00
Nickolay Ponomarev
aab0c36443 Support parsing constraints in CREATE TABLE
<table element> ::= ... | <table constraint definition> | ...
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#table-element-list
2019-06-02 13:54:16 +03:00
Nickolay Ponomarev
c69a1881c7 Change ALTER TABLE constraints parsing
- merge PrimaryKey and UniqueKey variants
- support `CHECK` constraints, removing the separate `Key` struct
- make `CONSTRAINT constraint_name` optional
- remove `KEY` without qualifiers (wasn't parsed and there doesn't
  appear to be such a thing)
- change `UNIQUE KEY` -> `UNIQUE`
- change `REMOVE CONSTRAINT` -> `DROP CONSTRAINT` and note its parsing
  is not implemented

Spec:
- ANSI SQL: see <table constraint definition> in https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#_11_6_table_constraint_definition
- Postgres: look for "and table_constraint is:" in https://www.postgresql.org/docs/11/sql-altertable.html
2019-06-02 13:54:11 +03:00
Nickolay Ponomarev
93c9000102 [mssql] Support single-quoted column aliases 2019-06-02 13:48:14 +03:00
Nickolay Ponomarev
d0a782d8cc [mssql] Support delimited identifiers in [square brackets]
T-SQL supports non-standard `[...]` quoting in addition to the widely
supported and standard `"..."`:

https://docs.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-2017
2019-06-02 13:48:14 +03:00
Nickolay Ponomarev
e6f5ff2926 [example-cli] Support parsing with different dialects 2019-06-02 13:48:14 +03:00
Nickolay Ponomarev
721c24188a
Merge pull request #69 from thomas-jeepe/master
Add FETCH and OFFSET support, and LATERAL <derived table>
2019-06-02 13:43:39 +03:00
Nikhil Benesch
90bcf55a6a
Fix the precedence of NOT LIKE
NOT LIKE has the same precedence as the LIKE operator. The parser was
previously assigning it the precedence of the unary NOT operator. NOT
BETWEEN and NOT IN are treated similarly, as they are equivalent, from a
precedence perspective, to NOT LIKE.

The fix for this requires associating precedences with sequences of
tokens, rather than single tokens, so that "NOT LIKE" and "NOT <expr>"
can have different preferences. Perhaps surprisingly, this change is not
very invasive.

An alternative I considered involved adjusting the tokenizer to lex
NOT, NOT LIKE, NOT BETWEEN, and NOT IN as separate tokens. This broke
symmetry in strange ways, though, as NotLike, NotBetween, and NotIn
gained dedicated tokens, while LIKE, BETWEEN, and IN remained as
stringly identifiers.

Fixes #81.
2019-06-01 02:52:18 -04:00
Nikhil Benesch
f55e3d5305
Introduce a peek_nth_token method
This will be used in a future commit, where looking ahead by two tokens
is important.
2019-05-31 18:18:28 -04:00
Justin Haug
2d00ea7187
Add lateral derived support 2019-05-31 18:10:25 -04:00
Justin Haug
fe10fac0ad
Add FETCH and OFFSET support 2019-05-31 18:10:24 -04:00
Nikhil Benesch
202464a06a
Merge pull request #68 from ivanceras/master
Add LIMIT as RESERVED_FOR_TABLE_ALIAS
2019-05-31 18:08:26 -04:00
Nikhil Benesch
d5fcd34438
Run CI on stable Rust
The nightly toolchain often doesn't have clippy available. Plus, it's
useful to verify we're not inadvertently depending on any nightly
features.
2019-05-31 18:06:51 -04:00
Nikhil Benesch
b2c93bd969
Enforce clippy and rustfmt in CI 2019-05-31 18:06:51 -04:00
Nickolay Ponomarev
d80f9f3a7a
Merge pull request #80 from benesch/between-expr
Support nested expressions in BETWEEN
2019-05-30 02:37:06 +03:00
Nickolay Ponomarev
646479e56c
Merge pull request #77 from benesch/count-distinct
Support COUNT(DISTINCT x) and similar
2019-05-30 02:35:49 +03:00
Nickolay Ponomarev
86a2fbd8e4
Merge pull request #76 from benesch/select-all
Support SELECT ALL
2019-05-30 02:35:18 +03:00
Nickolay Ponomarev
7a6a66bdc5
Merge pull request #75 from benesch/drop
Support DROP [TABLE|VIEW]
2019-05-30 02:33:33 +03:00
Nickolay Ponomarev
80f594e8d3
Merge pull request #73 from benesch/option-vec
Replace Option<Vec<T>> with Vec<T>
2019-05-30 02:32:35 +03:00
Nickolay Ponomarev
bc1ec47e4b
Merge pull request #72 from benesch/error
Implement std::error::Error for ParserError
2019-05-30 02:32:02 +03:00
Jamie Brandon
72ced4bffe
Support COUNT(DISTINCT x) and similar 2019-05-28 16:59:05 -04:00
Nikhil Benesch
ba21ce9d37
Support nested expressions in BETWEEN
`BETWEEN <thing> AND <thing>` allows <thing> to be any expr that doesn't
contain boolean operators. (Allowing boolean operators would wreak
havoc, because of the repurposing of AND as both a boolean operation
and part of the syntax of BETWEEN.)
2019-05-28 16:42:11 -04:00
Nikhil Benesch
187376e657
Support DROP [TABLE|VIEW]
Co-authored-by: Jamie Brandon <jamie@scattered-thoughts.net>
2019-05-26 19:57:33 -04:00
Nikhil Benesch
373a9265a2
Implement std::error::Error for ParserError 2019-05-26 18:59:43 -04:00
Jamie Brandon
55fc8c5a57
Support SELECT ALL
Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-05-26 18:57:04 -04:00
Nikhil Benesch
5652b4676c
Replace Option<Vec<T>> with Vec<T>
Vectors can already represent the absence of any arguments (i.e., by
being empty), so there is no need to wrap them in an Option.
2019-05-22 11:42:28 -04:00
Nickolay Ponomarev
4f944dd4aa
Merge pull request #71 from benesch/infix
Don't panic when NOT is not followed by an expected keyword
2019-05-22 01:18:23 +03:00
Jamie Brandon
143846d333
Don't panic on weird infix garbage
Co-authored-by: Nikhil Benesch <nikhil.benesch@gmail.com>
2019-05-21 11:59:45 -04:00
Jovansonlee Cesar
24f3d06231 Restore the original spacing in sqlparser.rs 2019-05-18 10:59:52 +08:00
Jovansonlee Cesar
d263d285e2 Add LIMIT as RESERVED_FOR_TABLE_ALIAS, this closes Issue#67 2019-05-18 10:53:19 +08:00
Nickolay Ponomarev
908082d26f
Merge pull request #63 from nickolay/pr/refactor-keywords
Use smarter macros to avoid duplication in keywords.rs
2019-05-12 01:06:12 +03:00
Nickolay Ponomarev
3d1b73ad1a
Merge pull request #64 from nickolay/pr/collate-cte-ne
Implement COLLATE, optional column list in CTEs, and more
2019-05-12 01:05:27 +03:00
Nickolay Ponomarev
5f3150e39a Add IsOptional enum to use instead of optional: bool
The meaning of `self.parse_parenthesized_column_list(false)?` was not
very obvious.
2019-05-08 03:23:44 +03:00
Nickolay Ponomarev
eeae3af6a3 Change the default serialization of "not equals" operator to <>
`!=` is not standard, though widely supported - https://stackoverflow.com/a/723426/1026
2019-05-06 22:20:29 +03:00
Nickolay Ponomarev
f93e69d1d4 Add parse_parenthesized_column_list to reduce code duplication 2019-05-06 22:20:29 +03:00
Nickolay Ponomarev
cccf7f0d8e Parse an optional column list after a CTE 2019-05-06 22:20:29 +03:00
Nickolay Ponomarev
f859c9b80e Support COLLATE in expressions
Roughly the <character factor> production - https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#character-factor

If an expression is followed by the keyword `COLLATE`, it must be
followed by the collation name, which is optionally schema-qualified
identifier.

The `COLLATE` keyword is not a regular binary operator in that it can't
be "nested": `foo COLLATE bar COLLATE baz` is not valid. If you prefer
to think of it as an operator, you might say it has the highest
precedence (judging from the spec), i.e. it binds to the smallest valid
expression to the left of it (so in `foo < bar COLLATE c`, the COLLATE
is applied first).
2019-05-06 22:20:29 +03:00
Nickolay Ponomarev
e7949d493c Reduce indentation in parse_prefix() 2019-05-06 22:20:29 +03:00
Nickolay Ponomarev
f82dc74e38 Mention that we use rustfmt for code formatting
...and add a `rustfmt.toml` as advised in https://www.reddit.com/r/rust/comments/9jl6a9/pro_tip_if_you_use_cargo_fmtrustfmt_use_a/
2019-05-06 22:20:29 +03:00
Andy Grove
037c6dab93
Merge pull request #61 from nickolay/pr/revamp-tests
Reorganize tests, remove datetime code, and add basic MSSQL dialect
2019-05-06 07:17:19 -06:00
Nickolay Ponomarev
ed20b8dde8 Use smarter macros to avoid duplication in keywords.rs 2019-05-04 16:58:58 +03:00
Nickolay Ponomarev
67cc880fd1 Add comments to the test files 2019-05-04 02:43:00 +03:00
Nickolay Ponomarev
304710d59a Add MSSQL dialect and fix up the postgres' identifier rules
The `@@version` test is MS' dialect of SQL, it seems, so test it with
its own dialect.

Update the rules for identifiers in Postresql dialect per documentation,
while we're at it. The current identifier rules in Postgresql dialect
were introduced in this commit - as a copy of generic rules, it seems:
810cd8e6cf (diff-2808df0fba0aed85f9d35c167bd6a5f1L138)
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
5047f2c02e Remove the ansi-specific test file and update PG tests
- The ANSI dialect is now tested in `sqlparser_common.rs`
- Some PG testcases are also parsed by the generic dialect successfully,
  so test that.
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
1347ca0825 Move the rest of tests not specific to PG from the sqlparser_postgres.rs 2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
478dbe940d Factor test helpers into a common module
Also run "generic" tests with all dialects (`parse_select_version`
doesn't work with ANSI dialect, so I moved it to the postgres file
temporarily)
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
de177f107c Remove dead datetime-related code
1) Removed unused date/time parsing methods from `Parser`

I don't see how the token-based parsing code would ever be used: the
date/time literals are usually quoted, like `DATE 'yyyy-mm-dd'` or
simply `'YYYYMMDD'`, so the date will be a single token.

2) Removed unused date/time related variants from `Value` and the
dependency on `chrono`.

We don't support parsing date/time literals at the moment and when we
do I think we should store the exact String to let the consumer parse
it as they see fit.

3) Removed `parse_timestamps_example` and
`parse_timestamps_with_millis_example` tests. They parsed as
`number(2016) minus number(02) minus number(15) <END OF EXPRESSION>`
(leaving the time part unparsed) as it makes no sense to try parsing
a yyyy-mm-dd value as an SQL expression.
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
9297ffbe18 Move tests using standard SQL from the postgresql-specific file 2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
d1b088bd43 Switch remaining tests to the standard format 2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
0233604f9b Remove extraneous tests
`parse_example_value` parses as compound identifier, which makes no
sense ("SARAH"."LEWISE@sakilacustomer"."org")

`parse_function_now` is unnecessary since we already test the parsing
of functions in `parse_scalar_function_in_projection`
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
fe635350f0 Improve INSERT tests
De-duplicate and check for specific error in `parse_insert_invalid`.
2019-05-04 01:00:13 +03:00
Nickolay Ponomarev
d58bbb8f9f Update doc comments
(The `SQLBetween` change is to fix a `cargo doc` warning.)
2019-05-02 21:30:32 +03:00
Andy Grove
4b27db0bf9
Merge pull request #59 from nickolay/next
Cleanups, and support `CASE operand`, TVFs and MSSQL-specific WITH hints
2019-04-27 15:13:47 -06:00
Nickolay Ponomarev
364f62f333 Parse table-valued functions and MSSQL-specific WITH hints
1) Table-valued functions (`FROM possibly_qualified.fn(arg1, ...)`) is
not part of ANSI SQL, but is supported in Postgres and MSSQL at least:
- "38.5.7. SQL Functions as Table Sources" <https://www.postgresql.org/docs/current/xfunc-sql.html#XFUNC-SQL-TABLE-FUNCTIONS>
- `user_defined_function` in "FROM (Transact-SQL)" <https://docs.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql?view=sql-server-2017>

I've considered renaming TableFactor::Table to something else (Object?),
now that it can be a TVF, but couldn't come up with a satisfactory name.

2) "WITH hints" is MSSQL-specific syntax
<https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-2017>

Note that MSSQL supports the following ways of specifying hints, which
are parsed with varying degrees of accuracy:
- `FROM tab (NOLOCK)` -- deprecated syntax, parsed as a function with a `NOLOCK` argument
- `FROM tab C (NOLOCK)` -- deprecated syntax, rejected ATM
- `FROM TAB C WITH (NOLOCK)` -- OK
2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
e5e3d71354 Support CASE operand WHEN expected_value THEN ..
Another part of #15
2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
2aa4c267e7 Simplify CASE parsing 2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
e5c0c426b7 Simplify parse_infix()
- ASTNode::SQLBinaryExpr is now constructed in one location
- There's no duplicate calls to parse_in/parse_between
- The list of tokens that correspond to operators is not duplicated
  in parse_infix / to_sql_operator
- ...which made it easy to distinguish between errors that could be
  caused by invalid input and internal errors. I switched the latter
  to `panic!()`
2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
d65274bc31 Improve ALTER error messages for unsupported syntax 2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
787cd9a717 Add Parser::expected() for more succinct error handling 2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
c679c7a5b4 Remove Value::Uuid
We don't have the code to parse UUID literals, so it's dead code, that
brings in the dependency on `uuid`.

I kept SQLType::Uuid, as it's not dead code, though it ought to be
dialect-specific.
2019-04-27 21:14:18 +03:00
Nickolay Ponomarev
6bb2acc9f8
Merge pull request #50 from nickolay/window-functions
Support OVER clause for window/analytic functions, add support for qualified function names
2019-04-27 21:12:08 +03:00
Andy Grove
64b1ea7a25
Merge pull request #54 from nickolay/windows-newlines
Support \r and \r\n line breaks in tokenizer
2019-04-27 08:54:20 -06:00
Andy Grove
07d66a93ef
Merge pull request #53 from thomas-jeepe/master
Fix qualified wildcard stringifying
2019-04-27 08:53:08 -06:00
Andy Grove
4cdd003cd4
Merge pull request #51 from nickolay/rust-2018
Rust 2018 and clippy fixes
2019-04-27 08:51:43 -06:00
Nickolay Ponomarev
bf3110f6ce Use consume_and_return when possible 2019-04-27 02:51:10 +03:00
Nickolay Ponomarev
6f44494910 Support \r and \r\n line breaks in tokenizer 2019-04-26 02:53:39 +03:00
Justin Haug
76d2d46496 run cargo fmt 2019-04-22 18:06:00 -04:00
Justin Haug
f9fb4bedfb Move wildcard test to generic parser 2019-04-22 17:52:15 -04:00
Justin Haug
80aceba630 run cargo fmt 2019-04-22 17:50:12 -04:00
Justin Haug
80dccf6885 Add support for escaping single quote strings 2019-04-22 13:32:05 -04:00
Justin Haug
5b464e6b1a Fix qualified wildcard stringifying 2019-04-22 13:10:29 -04:00
Nickolay Ponomarev
098d1c4a17 Enable clippy lints by default in RLS 2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
50a2310173 Rename SQLStatement::SQLSelect to SQLQuery
The name was confusing:
SQLStatement::SQLSelect(
  SQLQuery {
    body: SQLSetExpr::Select(SQLSelect)
  }
)

Fix the `large_enum_variant` clippy lint for `SQLStatement::SQLQuery`
`SQLStatement::SQLCreateView`, and `SQLSetExpr::Select`, while we're
changing the AST anyway
https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
08bbce8992 Use assert_matches! instead of matching manually
To fix clippy warnings about assert!(true / false)
2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
dee30aabe0 Fix the clippy assert!(false) lint
https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants

While I don't feel it's valid, fixing it lets us act on the other, more
useful, lints.
2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
a3a8626e6b Fix a clippy lint and reduce duplication in SQLType::to_string() 2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
c223eaf0aa Fix a bunch of trivial clippy lints 2019-04-21 04:46:19 +03:00
Nickolay Ponomarev
3df2223d95 Fix clippy if_same_then_else lint
https://rust-lang.github.io/rust-clippy/master/#if_same_then_else

There was a bug in parsing `TIME` (not followed by {WITH | WITHOUT}
TIME ZONE) -- that parsed as SQLType::Timestamp instead of SQLType::Time
2019-04-21 04:41:11 +03:00
Nickolay Ponomarev
0634ec4a83 Apply suggestions from cargo fix --edition-idioms 2019-04-21 04:41:11 +03:00
Nickolay Ponomarev
b12a19e197 Switch to the Rust 2018 edition
This requires Rust 1.31 (from last year) to build, but is otherwise
compatible with the 2015-edition code.
2019-04-21 04:41:11 +03:00
Nickolay Ponomarev
9a244e059e Fix clippy lints in "Support qualified function names" 2019-04-21 02:05:36 +03:00
Nickolay Ponomarev
de057deff6 Fix clippy lints in comma_separated_string 2019-04-21 02:05:36 +03:00
Nickolay Ponomarev
8c7e1d1c54 Update sample output in README 2019-04-20 22:51:29 +03:00
Nickolay Ponomarev
085e8a6b04 Use named fields in ExpressionWithAlias instead of a tuple
(This produces more natural JSON representation when serializing AST
with serde.)
2019-04-20 22:51:29 +03:00
Nickolay Ponomarev
4a5dc8dd4b Support qualified function names
...e.g. `db.schema.func()`
2019-04-20 22:51:29 +03:00
Nickolay Ponomarev
d4de248c73 Support OVER clause for window/analytic functions
Since this changes SQLFunction anyway, changed its `id` field to `name`,
as we don't seem to use "id" to mean "name" anywhere else.
2019-04-20 22:51:29 +03:00
Nickolay Ponomarev
c8e7c3b343 Introduce comma_separated_string() to reduce boilerplate in ToString impls 2019-04-20 22:51:29 +03:00
Andy Grove
ef76baa7fd (cargo-release) start next development iteration 0.3.1 2019-04-20 07:33:37 -06:00
Andy Grove
1aa4733890 bump version 2019-04-20 07:33:21 -06:00
Andy Grove
6ebd5dd819
Merge pull request #49 from nickolay/select-distinct
Support SELECT DISTINCT, and a few minor tweaks
2019-04-20 07:26:13 -06:00
Nickolay Ponomarev
bbf1805729 Support SELECT DISTINCT 2019-04-20 14:21:26 +03:00
Nickolay Ponomarev
31b6076d05 Use the same order in #[derive()] for all AST types
(So that adding another trait can be done with a global search and replace.)
2019-04-20 14:21:26 +03:00
Nickolay Ponomarev
e113dee7e8 Fix error text for unexpected token after NOT 2019-04-20 14:21:26 +03:00
Nickolay Ponomarev
5263ee1e9e Reduce nesting of ifs in SQLType::Decimal::to_string() 2019-04-20 14:21:26 +03:00
Nickolay Ponomarev
451513db5b Simplify parse_function() 2019-04-20 14:21:26 +03:00
Andy Grove
d9591cd999
Merge pull request #46 from zhzy0077/feature/external_table
Thanks @zhzy0077 !
2019-04-13 11:32:38 -06:00
Zhiyuan Zheng
d8f824c400 merge CreateExternalTable & CreateTable. 2019-04-14 01:05:26 +08:00
Zhiyuan Zheng
35556593f5
Delete test sql file. 2019-04-11 10:53:33 +08:00
Zhiyuan Zheng
26940920ac Add unit tests. 2019-04-09 13:28:01 +08:00
Zhiyuan Zheng
f0f6082eff support create external table 2019-04-08 21:36:02 +08:00
Andy Grove
d1b5668fd3
Merge pull request #43 from nickolay/master 2019-04-02 21:27:30 -06:00
Nickolay Ponomarev
311f2ab429 bump version to 0.3.0, as requested in the PR 2019-04-02 09:46:21 +03:00
Nickolay Ponomarev
5de23b1e78 Merge branch 'upstream' 2019-04-02 09:16:51 +03:00
Nickolay Ponomarev
6dfe7c2413 reapply the "Rework keyword/identifier parsing" PR 2019-04-02 09:15:15 +03:00
Andy Grove
bebaec4c79
Merge pull request #45 from andygrove/update_gitter_badge
Update badge based on gitter email
2019-03-31 22:54:06 -06:00
Andy Grove
eee1b3a2bd Update badge based on gitter email 2019-03-31 22:53:08 -06:00
Nickolay Ponomarev
5ba9912a9d Merge remote-tracking branch 'upstream/master' 2019-03-08 17:29:54 +03:00
Andy Grove
aa1f0faad4 (cargo-release) start next development iteration 0.2.5-alpha.0 2019-03-08 07:28:37 -07:00
Andy Grove
30de48c840 (cargo-release) version 0.2.4 2019-03-08 07:28:29 -07:00
Andy Grove
4a355e6ddc
Merge pull request #42 from andygrove/revert-37-keywords
Revert "Rework keyword/identifier parsing"
2019-03-08 07:28:07 -07:00
Andy Grove
43f4c6875f
Revert "Rework keyword/identifier parsing" 2019-03-08 07:27:27 -07:00
Andy Grove
391c53d5c9 (cargo-release) start next development iteration 0.2.4-alpha.0 2019-03-08 07:20:19 -07:00
Andy Grove
6580bf10c0 (cargo-release) version 0.2.3 2019-03-08 07:20:08 -07:00
Andy Grove
75e2c0a64f
Merge pull request #37 from nickolay/keywords
Rework keyword/identifier parsing
2019-03-08 07:19:34 -07:00
Andy Grove
7c9f62962d
Merge branch 'master' into keywords 2019-03-08 06:24:24 -07:00
Andy Grove
8c1d6a67fa (cargo-release) start next development iteration 0.2.3-alpha.0 2019-03-08 06:15:48 -07:00
Andy Grove
15704f1fbe (cargo-release) version 0.2.2 2019-03-08 06:15:37 -07:00
Andy Grove
73f55fe1bb
Merge pull request #36 from nickolay/strings
Clean up string-related variants in Token and Value
2019-03-08 06:14:59 -07:00
Andy Grove
ff897b9086
Merge pull request #38 from nickolay/remove-duplicate-tests
Remove sqlparser_generic.rs/sqlparser_postgres.rs duplication
2019-03-08 06:09:25 -07:00
Nickolay Ponomarev
0621f8d43c Merge https://github.com/nickolay/sqlparser-rs/pull/1 from benesch/materialized 2019-03-08 15:49:53 +03:00
Nickolay Ponomarev
f30ab89ad2 Re-run cargo fmt 2019-03-08 15:46:40 +03:00
Nikhil Benesch
23a0fc79f5
Support CREATE MATERIALIZED VIEW 2019-03-07 13:14:33 -05:00
Nickolay Ponomarev
52e0f55b6f Support UNION/EXCEPT/INTERSECT 2019-02-11 05:14:36 +03:00
Nickolay Ponomarev
533775c0da Support CHAR synonym for CHARACTER
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#character-string-type
2019-02-11 05:14:34 +03:00
Nickolay Ponomarev
23a0d032bd Support NUMERIC without precision or scale
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#exact-numeric-type
2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
54c9ca8619 Support unary + / - 2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
786b1cf18a Support BETWEEN 2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
264319347d Support IN 2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
bed03abe44 Support AS and qualified wildcards in SELECT 2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
bf0c07bb1b Support basic CTEs (WITH)
Some unsupported features are noted as TODOs.
2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
f958e9d3cf TBD fixup multiline comment tokenization 2019-02-11 05:13:48 +03:00
Nickolay Ponomarev
028c613c3f Support comments in the tokenizer 2019-02-07 05:34:38 +03:00
Nickolay Ponomarev
35dd9342e2 Support national string literals (N'...')
Widely used in MS SQL and specified in ANSI.
2019-02-07 05:34:33 +03:00
Nickolay Ponomarev
b9f4b503b6 Support different quoting styles for delimited identifiers
The dialect information is from https://en.wikibooks.org/wiki/SQL_Dialects_Reference/Data_structure_definition/Delimited_identifiers
2019-02-07 05:34:29 +03:00
Nickolay Ponomarev
b3693bfa63 Simplify quoted identifier tokenization 2019-02-07 05:34:26 +03:00
Nickolay Ponomarev
2e9da53ed3 Small CLI app that can be used to test parsing an external SQL file 2019-02-07 05:34:16 +03:00
Nickolay Ponomarev
577e634f3c Update README to the recent changes in the AST 2019-02-07 05:34:16 +03:00
Nickolay Ponomarev
0c0cbcaff4 Support basic CREATE VIEW 2019-02-07 05:34:12 +03:00
Nickolay Ponomarev
346d1ff2e4 Improve error messages in parse_create()
By not swallowing the Err from parse_data_type().

Also switch to `match` to enable parsing table-level constraints in this
loop later.
2019-02-07 05:34:09 +03:00
Nickolay Ponomarev
a0f625b949 Simplify parse_create() a little
Don't need the duplicate `columns.push()` + we advance the tokenizer,
so no need to peek first.
2019-02-07 05:34:06 +03:00
Nickolay Ponomarev
89602dc044 Fix a typo in parse_value error message 2019-02-07 05:34:03 +03:00
Nickolay Ponomarev
b716ffb937 Simplify JOIN USING (columns)
...by reusing `parse_column_names` instead of extracting identifiers
out of the `parse_expr_list`s result.
2019-02-07 05:34:00 +03:00
Nickolay Ponomarev
05a70a358a Assert when an unknown keyword was passed to parse_keyword()
This happens all the time when I forget to check that the keyword I wanted
to use is actually listed in keywords.rs, this should help with debugging.
2019-02-07 05:33:57 +03:00
Nickolay Ponomarev
6b107065ac Switch some tests to verified_select_stmt
(the tests affected by "unboxing" in the previous commits.)
2019-02-07 05:33:54 +03:00
Nickolay Ponomarev
e3b981a0e2 Don't Box<ASTNode> in SQLSelect
Instead change ASTNode::SQLSubquery to be Box<SQLSelect>
2019-02-07 05:33:51 +03:00
Nickolay Ponomarev
c5bbfc33fd Don't Box<ASTNode> in SQLStatement
This used to be needed when it was a variant in the ASTNode enum itself.
2019-02-07 05:33:46 +03:00
Nickolay Ponomarev
3619e89e9c Remove Box<> from SQLOrderByExpr
It was probably copied from somewhere else when most types were variants
in ASTNode, and needed Box<> to prevent recursion in the ASTNode definition.
2019-02-07 05:33:43 +03:00
Nickolay Ponomarev
9967031cba Move TableFactor to be a separate enum
ASTNode can now be renamed SQLExpression, as it represents a node in
the "expression" part of the AST -- other nodes have their own types.
2019-02-07 05:33:41 +03:00
Nickolay Ponomarev
e0ceacd1ad Store original, quoted form in SQLIdent
Also move more things to use SQLIdent instead of String in the hope of
making it a newtype eventually.

Add tests that quoted identifiers round-trip parsing/serialization correctly.
2019-02-07 05:33:12 +03:00
Nickolay Ponomarev
07790fe4c4 Improve DELETE FROM parsing (4.4/4.4)
Store (and parse) `table_name: SQLObjectName` instead of
`relation: Option<Box<ASTNode>>`, which can be an arbitrary expression.

Also remove the `Option<>`: the table name is not optional in any dialects
I'm familiar with. While the FROM keyword itself _is_ optional in some
dialects, there are more things to implement for those dialects, see
https://stackoverflow.com/a/4484271/1026
2019-02-07 05:31:51 +03:00
Nickolay Ponomarev
f5bd9c398f Simplify by avoiding SQLCompoundIdentifier (4.3/4.4)
...instead make `parse_compound_identifier()` return the underlying
Vec<> directly, and rename it to `parse_list_of_ids()`, since it's
used both for parsing compound identifiers and lists of identifiers.
2019-02-07 05:31:47 +03:00
Nickolay Ponomarev
39e98cb11a Rename parse_tablename -> parse_object_name (4.2/4.4)
...to match the name of the recently introduced `SQLObjectName` struct
and to avoid any reservations about using it with multi-part names of
objects other than tables (as in the `type_name` case).
2019-02-07 05:31:44 +03:00
Nickolay Ponomarev
523f086be7 Introduce SQLObjectName struct (4.1/4.4)
(To store "A name of a table, view, custom type, etc., possibly
multi-part, i.e. db.schema.obj".)

Before this change

  - some places used `String` for this (these are updated in this commit)

  - while others (notably SQLStatement::SQLDelete::relation, which is
    the reason for this series of commits) relied on
    ASTNode::SQLCompoundIdentifier (which is also backed by a 
    Vec<SQLIdent>, but, as a variant of ASTNode enum, is not convenient
    to use when you know you need that specific variant).
2019-02-07 05:31:40 +03:00
Nickolay Ponomarev
215820ef66 Stricter parsing for subqueries (3/4)
This makes the parser more strict when handling SELECTs nested
somewhere in the main statement:

1) instead of accepting SELECT anywhere in the expression where an
   operand was expected, we only accept it inside parens. (I've added a
   test for the currently supported syntax, <scalar subquery> in ANSI
   SQL terms)

2) instead of accepting any expression in the derived table context:
   `FROM ( ... )` - we only look for a SELECT subquery there.

Due to #1, I had to swith the 'ansi' test from invoking the expression
parser to the statement parser.
2019-02-07 05:31:36 +03:00
Nickolay Ponomarev
82dc581639 Fix precedence for the NOT operator (2/4)
I checked the docs of a few of the most popular RDBMSes, and it seems
there's consensus that the precedence of `NOT` is higher than `AND`,
but lower than `IS NULL`.

Postgresql[1], Oracle[2] and MySQL[3] docs say that explicitly.

T-SQL docs[4] do mention it's higher than `AND`, and while they don't
explicitly mention IS NULL, this snippet:

    select * from (select 1 as a)x
    where (not x.a) is null

...is a parsing error, while the following works like IS NOT NULL:

    select * from (select 1 as a)x
    where not x.a is null

sqlite doesn't seem to mention `NOT` precedence, but I assume it works
similarly.

[1] https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-OPERATORS
[2] https://docs.oracle.com/cd/B19306_01/server.102/b14200/conditions001.htm#i1034834
[3] https://dev.mysql.com/doc/refman/8.0/en/operator-precedence.html
[4] https://docs.microsoft.com/en-us/sql/t-sql/language-elements/operator-precedence-transact-sql?view=sql-server-2017
2019-02-07 05:24:55 +03:00
Nickolay Ponomarev
29db619792 Stop losing parens when roundtripping (1/4)
Before this change an expression like `(a+b)-(c+d)` was parsed correctly
(as a Minus node with two Plus nodes as children), but when serializing
back to an SQL string, it came up as a+b-c+d, since we don't store
parens in AST and don't attempt to insert them when necessary during
serialization. The latter would be hard, and we already had an SQLNested
enum variant, so I changed the code to wrap the AST node for the
parenthesized expression in it.
2019-02-07 05:24:54 +03:00
Nickolay Ponomarev
b57c60a78c Only use parse_expr() when we expect an expression (0/4)
Before this commit there was a single `parse_expr(u8)` method, which
was called both

1) from within the expression parser (to parse subexpression consisting
   of operators with higher priority than the current one), and

2) from the top-down parser both

   a) to parse true expressions (such as an item of the SELECT list or
      the condition after WHERE or after ON), and 
   b) to parse sequences which are not exactly "expressions".


This starts cleaning this up by renaming the `parse_expr(u8)` method to
`parse_subexpr()` and using it only for (1) - i.e. usually providing a
non-zero precedence parameter.

The non-intuitively called `parse()` method is renamed to `parse_expr()`,
which became available and is used for (2a).


While reviewing the existing callers of `parse_expr`, four points to
follow up on were identified (marked "TBD (#)" in the commit):

1) Do not lose parens (e.g. `(1+2)*3`) when roundtripping
   String->AST->String by using SQLNested.
2) Incorrect precedence of the NOT unary
3) `parse_table_factor` accepts any expression where a SELECT subquery
   is expected.
4) parse_delete uses parse_expr() to retrieve a table name

These are dealt with in the commits to follow.
2019-02-07 05:24:54 +03:00
Nickolay Ponomarev
707c58ad57 Support parsing of multiple statements (5/5)
Parser::parse_sql() can now parse a semicolon-separated list of
statements, returning them in a Vec<SQLStatement>.

To support this we:

  - Move handling of inter-statement tokens from the end of individual
    statement parsers (`parse_select` and `parse_delete`; this was not
    implemented for other top-level statements) to the common
    statement-list parsing code (`parse_sql`);

  - Change the "Unexpected token at end of ..." error, which didn't have
    tests and prevented us from parsing successive statements  ->
    "Expected end of statement" (i.e. a delimiter - currently only ";" -
    or the EOF);

  - Add PartialEq on ParserError to be able to assert_eq!() that parsing
    statements that do not terminate properly returns an expected error.
2019-02-07 05:24:54 +03:00
Nickolay Ponomarev
5a0e0ec928 Simplify some tests by introducing verified_select_stmt and expr_from_projection
(The primary motivation was that it makes the tests more resilient to
the upcoming changes to the SQLSelectStatement to support `AS` aliases
and `UNION`.)

Also start using `&'static str` literals consistently instead of
String::from for the `let sql` test strings.
2019-02-07 05:24:54 +03:00
Nickolay Ponomarev
2dec65fdb4 Separate statement from expr parsing (4/5)
Continuing from https://github.com/andygrove/sqlparser-rs/pull/33#issuecomment-453060427

This stops the parser from accepting (and the AST from being able to
represent) SQL look-alike code that makes no sense, e.g.

    SELECT ... FROM (CREATE TABLE ...) foo
    SELECT ... FROM (1+CAST(...)) foo

Generally this makes the AST less "partially typed": meaning certain
parts are strongly typed (e.g. SELECT can only contain projections,
relations, etc.), while everything that didn't get its own type is
dumped into ASTNode, effectively untyped. After a few more fixes (yet
to be implemented), `ASTNode` could become an `SQLExpression`. The
Pratt-style expression parser (returning an SQLExpression) would be
invoked from the top-down parser in places where a generic expression
is expected (e.g. after SELECT <...>, WHERE <...>, etc.), while things
like select's `projection` and `relation` could be more appropriately
(narrowly) typed.


Since the diff is quite large due to necessarily large number of
mechanical changes, here's an overview:

1) Interface changes:

   - A new AST enum - `SQLStatement` - is split out of ASTNode:

     - The variants of the ASTNode enum, which _only_ make sense as a top
       level statement (INSERT, UPDATE, DELETE, CREATE, ALTER, COPY) are
       _moved_ to the new enum, with no other changes.
     - SQLSelect is _duplicated_: now available both as a variant in
       SQLStatement::SQLSelect (top-level SELECT) and ASTNode:: (subquery).

   - The main entry point (Parser::parse_sql) now expects an SQL statement
     as input, and returns an `SQLStatement`.

2) Parser changes: instead of detecting the top-level constructs deep
down in the precedence parser (`parse_prefix`) we are able to do it
just right after setting up the parser in the `parse_sql` entry point

(SELECT, again, is kept in the expression parser to demonstrate how
subqueries could be implemented).

The rest of parser changes are mechanical ASTNode -> SQLStatement
replacements resulting from the AST change.

3) Testing changes: for every test - depending on whether the input was
a complete statement or an expresssion -  I used an appropriate helper
function:

   - `verified` (parses SQL, checks that it round-trips, and returns
     the AST) - was replaced by `verified_stmt` or `verified_expr`.

   - `parse_sql` (which returned AST without checking it round-tripped)
     was replaced by:

     - `parse_sql_expr` (same function, for expressions)

     - `one_statement_parses_to` (formerly `parses_to`), extended to
       deal with statements that are not expected to round-trip.
       The weird name is to reduce further churn when implementing
       multi-statement parsing.

     - `verified_stmt` (in 4 testcases that actually round-tripped)
2019-01-31 15:54:57 +03:00
Nickolay Ponomarev
50b5724c39 Don't parse ORDER BY as a table alias (8/8) 2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
7b86f5c842 Remove unused ASTNode::SQLAssignment variant (3/5)
The SQLAssignment *struct* is used directly in ASTNode::SQLUpdate (will
change to SQLStatement::SQLUpdate shortly).
2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
76ec175d20 Support table aliases without AS (7/8)
...as in `FROM foo bar WHERE bar.x > 1`.

To avoid ambiguity as to whether a token is an alias or a keyword, we
maintain a blacklist of keywords, that can follow a "table factor", to
prevent parsing them as an alias. This "context-specific reserved
keyword" approach lets us accept more SQL that's valid in some dialects,
than a list of globally reserved keywords. Also some dialects (e.g.
Oracle) apparently don't reserve some keywords (like JOIN), while
presumably they won't accept them as an alias (`FROM foo JOIN` meaning
`FROM foo AS JOIN`).
2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
45a5f844af Move SQLOrderByExpr and Join* to query.rs (2/5) 2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
536fa6e428 Support AS table aliases (6/8)
A "table factor" (name borrowed from the ANSI SQL grammar) is a table
name or a derived table (subquery), followed by an optional `AS` and an
optional alias. (The alias is *not* optional for subqueries, but we
don't enforce that.) It can appear in the FROM/JOIN part of the query.

This commit:
- introduces ASTNode::TableFactor
- changes the parser to populate SQLSelect::relation and Join::relation
  with ASTNode::TableFactor instead of the table name
- changes the parser to only accept subqueries or identifiers, not
  arbitrary expressions in the "table factor" context
- always parses the table name as SQLCompoundIdentifier (whether or not
  it was actually compound).
2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
d8173d4196 Extract ASTNode::SQLSelect to a separate struct (1/5)
This will allow re-using it for SQLStatement in a later commit.

(Also split the new struct into a separate file, other query-related
types will be moved here in a follow-up commit.)
2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
7bbf69f513 Further simplify parse_compound_identifier (5/8)
This part changes behavior:
- Fail when no identifier is found.
- Avoid rewinding if EOF was hit right after the identifier.
2019-01-31 03:57:17 +03:00
Nickolay Ponomarev
991fd19b87 Stop nesting match in parse_compound_identifier (4/8) 2019-01-31 03:57:16 +03:00
Nickolay Ponomarev
8c3479969f Simplify by using expect_keyword / expect_token (3/8)
...instead of parse_keyword / consume_token - to reduce nesting of `if`s.

(Follow-up to PR #35)
2019-01-31 03:57:16 +03:00
Nickolay Ponomarev
f87230553e Remove dialect-specific keyword lists (2/8)
Now populating SQLWord.keyword based on the list of globally supported
keywords.
2019-01-31 03:57:16 +03:00
Nickolay Ponomarev
9a8b6a8e64 Rework keyword/identifier parsing (1/8)
Fold Token::{Keyword, Identifier, DoubleQuotedString} into one
Token::SQLWord, which has the necessary information (was it a
known keyword and/or was it quoted).

This lets the parser easily accept DoubleQuotedString (a quoted
identifier) everywhere it expects an Identifier in the same match
arm. (To complete support of quoted identifiers, or "delimited
identifiers" as the spec calls them, a TODO in parse_tablename()
ought to be addressed.)

    As an aside, per <https://en.wikibooks.org/wiki/SQL_Dialects_Reference/Data_structure_definition/Delimited_identifiers>
    sqlite seems to be the only one supporting 'identifier'
    (which is rather hairy, since it can also be a string
    literal), and `identifier` seems only to be supported by
    MySQL. I didn't implement either one.

This also allows the use of `parse`/`expect_keyword` machinery
for non-reserved keywords: previously they relied on the keyword
being a Token::Keyword, which wasn't a Token::Identifier, and so
wasn't accepted as one.

Now whether a keyword can be used as an identifier can be decided
by the parser. (I didn't add a blacklist of "reserved" keywords,
so that any keyword which doesn't have a special meaning in the
parser could be used as an identifier. The list of keywords in
the dialect could be re-used for that purpose at a later stage.)
2019-01-31 03:57:16 +03:00
Nickolay Ponomarev
eb4b5bc686 Stop returning Option from parse_infix
This reduces amount of boilerplate and avoids cloning the `expr` param.
2019-01-30 04:10:55 +03:00
Nickolay Ponomarev
d73a1e0e1d Join match arms for Keyword and binary ops
because they share implementation.
2019-01-30 04:10:55 +03:00
Nickolay Ponomarev
3de2a0952c Make SQLOrderByExpr::asc tri-state
i.e. ASC/DESC/unspecified - so that we don't lose information about
source code.

Also don't take any keyword other than ASC/DESC or Comma to mean
'ascending'.
2019-01-30 04:10:55 +03:00
Nickolay Ponomarev
12b9f5aafc Merge branches 'strings' and 'remove-duplicate-tests' 2019-01-20 19:30:36 +03:00
Nickolay Ponomarev
70c799e21d Use verified() in the remaining PG-specific tests 2019-01-20 19:30:13 +03:00
Nickolay Ponomarev
9441f9c5d8 Move tests for "LIKE '%'" to sqlparser_generic.rs
...as this syntax is not specific to the PostgreSQL dialect.

Also use verified() to assert that parsing + serializing results in the
original SQL string.
2019-01-20 19:30:12 +03:00
Nickolay Ponomarev
d5109a2880 Remove duplicate tests from sqlparser_postgres.rs
These have identical copies in sqlparser_generic.rs
2019-01-20 19:30:12 +03:00
Nickolay Ponomarev
078eb677a1 Remove Value::String
Its existence alongside SingleQuotedString simply doesn't make sense:
`'a string'` is a string literal, while `a string` is not a "value".

It's only used in postgresql-specific tab-separated-values parser to
store the string representation of a field's value. For that use-case
Option<String> looks like a more appropriate choice than Value.
2019-01-20 19:26:58 +03:00
Nickolay Ponomarev
56884dc700 Remove Value::DoubleQuotedString
...and parser support for the corresponding token, as "..." in SQL[*] is
not a literal string like we parse it - but a quoted identifier (which I
intend to implement later).

[*] in all the RBDMSes I know, except for sqlite which has complex rules
in the name of "compatibility": https://www.sqlite.org/lang_keywords.html
2019-01-20 19:26:58 +03:00
Nickolay Ponomarev
efdbf0f9dc Remove Token::Identifier match arm from parse_value
An identifier is not a literal value, and parse_value is not called on
such a token anyway.
2019-01-20 19:26:57 +03:00
Nickolay Ponomarev
d0a65ffd05 Remove Token::String, as it's never emitted
Indeed, given that there is Token::SingleQuotedString and
Token::Identifier, there's no other "string" that would make sense...
2019-01-20 19:26:57 +03:00
Nickolay Ponomarev
45dab0e2d4 Run all the 'generic' tests with the PostgreSqlDialect too. 2019-01-20 19:15:05 +03:00
Nickolay Ponomarev
a1da7b4005 Reduce differences between "generic" and "postgresql" tests
Mainly by replacing `assert_eq!(sql, ast.to_string())` with a call to
the recently introduced `verified()` helper or using `parses_to()` where
the expected serialization differs from the original SQL string.

There was one case (parse_implicit_join), where the inputs were different:
let sql = "SELECT * FROM t1,t2";
//vs
let sql = "SELECT * FROM t1, t2";

and since we don't test the whitespace handling in other tests, I just
used the canonical representation as input.
2019-01-20 19:14:53 +03:00
Andy Grove
82b1467324 (cargo-release) start next development iteration 0.2.2-alpha.0 2019-01-13 09:19:46 -07:00
Andy Grove
bde2e2d660 (cargo-release) version 0.2.1 2019-01-13 09:19:37 -07:00
Andy Grove
47e00af15b
Merge pull request #35 from nickolay/consume-token
Clean up consume_token() and parse/expect_keyword()
2019-01-13 09:16:13 -07:00
Nickolay Ponomarev
ae06dc7901 Return bool from consume_token(), mark as #[must_use] 2019-01-13 01:09:47 +03:00
Nickolay Ponomarev
fd9e2818d7 Introduce expect_token(), failing when the expected token was not found 2019-01-13 01:08:17 +03:00
Nickolay Ponomarev
b3ab4aca88 Use expect_keyword() instead of consume_token() where appropriate
Before this missing keywords THEN/WHEN/AS would be parsed as if they
were in the text as the code didn't check the return value of
consume_token() - see upcoming commit.
2019-01-13 01:07:58 +03:00
Nickolay Ponomarev
de4ccd3cb7 Fail when expected keyword is not found
Add #[must_use] to warn against unchecked results of parse_keyword/s in
the future.
2019-01-13 01:07:58 +03:00
Nickolay Ponomarev
89cfa9e599 Don't consume a second DoubleColon in parse_pg_cast
The function is invoked after a DoubleColon was already matched.
2019-01-13 01:07:58 +03:00
Nickolay Ponomarev
dce09f8054 Fix a mistake in merge conflict resolution earlier 2019-01-13 00:56:51 +03:00
Andy Grove
ac365bd44e (cargo-release) start next development iteration 0.2.1-alpha.0 2019-01-12 11:23:33 -07:00
Andy Grove
a987503b2c (cargo-release) version 0.2.0 2019-01-12 11:23:20 -07:00
Andy Grove
115c8e5595
Merge pull request #33 from andygrove/not
implement NOT
2019-01-12 11:19:59 -07:00
Andy Grove
c0cafb7308 specialized parser for DEFAULT expression in CREATE TABLE 2019-01-12 11:18:21 -07:00
Andy Grove
777fd4c2ee Merge branch 'master' into not 2019-01-12 11:14:07 -07:00
Andy Grove
a52b59e3ab Merge branch 'fredrikroos-join-support' 2019-01-12 11:11:28 -07:00
Andy Grove
f8c6fa96f4 fix regression 2019-01-12 11:11:18 -07:00
Andy Grove
8c351fe10a Merge branch 'join-support' of https://github.com/fredrikroos/sqlparser-rs into fredrikroos-join-support 2019-01-12 11:09:41 -07:00
Andy Grove
32d53a6b7e Update README 2019-01-12 10:00:00 -07:00
Andy Grove
7233a7e71f (cargo-release) start next development iteration 0.1.11-alpha.0 2019-01-12 09:30:19 -07:00
Andy Grove
81954bffb8 (cargo-release) version 0.1.10 2019-01-12 09:30:08 -07:00
Andy Grove
25718b8028
Merge pull request #34 from nickolay/misc
Miscellaneous fixes
2019-01-12 09:29:11 -07:00
Andy Grove
ab423bc9dc
Merge branch 'master' into join-support 2019-01-12 08:33:12 -07:00
Nickolay Ponomarev
3b13e153a8 Fix parse_time() handling of fractional seconds
There's no Token::Period in such situation, so fractional part (from sec) was silently truncated.

Can't uncomment the test yet, because parse_timestamp() is effectively
unused: the code added to parse_value() in 5abd9e7dec
was wrong as it attempted to handle unquoted date/time literals. One
part of it was commented out earlier, the other can't work as far as I
can see, as it tries to parse a Number token - `([0-9]|\.)+` - as a
timestamp, so I removed it as well.
2019-01-11 02:37:36 +03:00
Nickolay Ponomarev
52277c3025 Remove parse_function_or_pg_cast, since fn(...) :: type is taken care of in parse_infix() 2019-01-11 02:37:36 +03:00
Nickolay Ponomarev
eff92a2dc1 Remove special handling of ::type1::type2 from parse_pg_cast
...it gets handled just as well by the infix parser.
(Add a test while we're at it.)
2019-01-11 02:37:36 +03:00
Nickolay Ponomarev
f21cd697c3 Simplify custom datatypes handling and add a test
1) Simplified the bit in parse_datatype()
2) Made sure it was covered by the test (the "public.year" bit)
2a) ...the rest of changes in the test are to fix incorrect variable
 names: c_name/c_lat/c_lng were copy-pasted from a previous test.
3) Removed the branch from parse_pg_cast, which duplicated what
parse_data_type already handled (added in the same commit even
2007995938 )
2019-01-11 02:37:36 +03:00
Nickolay Ponomarev
7c6e6970fa Simplify the {next|prev|peek}_token functions
Remove `pub` from the "internal" ones. Remove ones that duplicate each
other completely.
2019-01-11 02:37:36 +03:00
Nickolay Ponomarev
2873b0cee2 Combine multiple patterns with the same action in parse_prefix() 2019-01-11 01:49:13 +03:00
Andy Grove
ee1944b9d9 Implemented NOT LIKE 2018-12-16 16:30:32 -07:00
Andy Grove
5d62167d6e rename rex to expr in ASTNode 2018-12-16 14:04:51 -07:00
Andy Grove
7aab880387 implement NOT 2018-12-16 14:03:03 -07:00
Andy Grove
2240dd09ff (cargo-release) start next development iteration 0.1.10-alpha.0 2018-12-16 13:57:25 -07:00
Andy Grove
d0b5d5e882 (cargo-release) version 0.1.9 2018-12-16 13:57:12 -07:00
Andy Grove
e863bc041c cargo fmt, fix compiler warnings 2018-12-16 13:57:01 -07:00
Andy Grove
24af049930
Merge pull request #32 from cswinter/like
Add LIKE operator
2018-12-16 13:54:00 -07:00
Clemens Winter
9d3906d655 Add LIKE token GenericSQLDialect 2018-12-16 11:47:01 -08:00
Clemens Winter
91aa985ed0 Add LIKE operator 2018-12-16 11:26:09 -08:00
Fredrik Roos
72024661a9 More tests and some small bugfixes 2018-11-18 00:53:39 +01:00
Fredrik Roos
7624095738 Support for joins 2018-11-17 15:40:24 +01:00
Andy Grove
face97226b
Merge pull request #27 from virattara/fix_select_semi_colon
consume semi colon at the end of select and delete queries
2018-10-17 17:05:34 -06:00
virattara
9898e99eb2 unit tests for select, delete statements ending with semi colon 2018-10-17 15:54:49 +05:30
virattara
b75a22ce2e consume semi colon at the end of select and delete queries 2018-10-17 15:52:11 +05:30
Andy Grove
70a3ae93c8
Merge pull request #25 from nickolay/master
Support "searched" CASE expressions
2018-10-16 20:03:34 -06:00
Andy Grove
7af4bb55e6 (cargo-release) start next development iteration 0.1.9-alpha.0 2018-10-14 12:27:05 -06:00
Andy Grove
ff4f1f0b94 (cargo-release) version 0.1.8 2018-10-14 12:26:54 -06:00
Andy Grove
7e152cd0a9 revert one timestamp parsing case 2018-10-14 12:26:47 -06:00
Andy Grove
249b99e48f (cargo-release) start next development iteration 0.1.8-alpha.0 2018-10-14 12:13:34 -06:00
Andy Grove
cc5a6c335d (cargo-release) version 0.1.7 2018-10-14 12:13:25 -06:00
Andy Grove
1bb7149670 bug fix 2018-10-14 12:12:23 -06:00
Nickolay Ponomarev
5a396bb9b4 Support "searched" CASE expressions (#15)
https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#searched-case
2018-10-14 20:45:32 +03:00
Andy Grove
5b7e89225b (cargo-release) start next development iteration 0.1.7-alpha.0 2018-10-14 11:43:13 -06:00
Andy Grove
8554ff1932 (cargo-release) version 0.1.6 2018-10-14 11:43:05 -06:00
Andy Grove
633aeb9162
Merge pull request #26 from virattara/fix_order_limit
fix for queries with both order by and limit
2018-10-14 10:13:22 -06:00
Andy Grove
038698c706
Merge pull request #24 from virattara/feat_paren_expr
added support for expressions with parentheses
2018-10-14 10:12:39 -06:00
virattara
9f47e8ac94 fix for queries with both order by and limit 2018-10-12 16:10:00 +05:30
virattara
94df7c22e6 added support for expressions with parentheses 2018-10-07 14:23:05 +05:30
Andy Grove
335607f6bb Add placeholder unit test for ANSI parser 2018-10-06 10:37:49 -06:00
Andy Grove
035ef52696 re-instate tests for generic parser 2018-10-06 10:15:10 -06:00
Andy Grove
beb1a7a735 clean up use of modules 2018-10-06 10:04:22 -06:00
Andy Grove
661ada0664 fix compiler warnings 2018-10-06 09:58:16 -06:00
Andy Grove
4b6967ccd6 remove unused variables 2018-10-06 09:40:30 -06:00
Andy Grove
722ea7a91b ran cargo fmt 2018-10-06 09:39:26 -06:00
Andy Grove
9daba3ab49 move tests to tests dir 2018-10-06 09:39:06 -06:00
Andy Grove
486eca1f10
Merge pull request #20 from ivanceras/master
Postgres dialect + various improvements
2018-10-06 09:28:39 -06:00
Jovansonlee Cesar
439f64dfe1 Make keywords public 2018-10-01 01:28:58 +08:00
Jovansonlee Cesar
24153aee53 keywords are now generated via macro to avoid misspellings, dialects should lookup to these list of keywords to avoid mispellings 2018-10-01 00:58:20 +08:00
Jovansonlee Cesar
d66e4848bd modularize dialects into their own submodules
remove assertion in copy sql, conversion to_string is unfinished
2018-09-30 13:35:24 +08:00
Andy Grove
e6ad7ab715
Merge pull request #21 from ivanceras/parse_insert
Implement parsing insert statement
2018-09-29 15:40:05 -06:00
Jovansonlee Cesar
ba8a9bd48f NULL need to be detected in COPY 2018-09-30 04:19:15 +08:00
Jovansonlee Cesar
5abd9e7dec Modularized into separate files
Add ToString implementation on the components
2018-09-30 03:34:37 +08:00
Jovansonlee Cesar
34913c7051 Implement alter table constraint operation 2018-09-29 19:37:03 +08:00
Jovansonlee Cesar
639f01d4e7 Make Uuid a datatype in PostgreSQL dialect 2018-09-29 13:50:33 +08:00
Jovansonlee Cesar
da153bf848 Make a PostgreSQLDialect
Add is_primary and is_unique in the column definition

Initial code for testing alter table
2018-09-28 03:32:10 +08:00
Jovansonlee Cesar
74b34faaf1 Also tokenize non alphanumeric characters into some Char, since they can be tab separated values in COPY payload 2018-09-26 23:59:52 +08:00
Jovansonlee Cesar
7c7b67b0bc testing values for most common data dump 2018-09-26 22:51:50 +08:00
Jovansonlee Cesar
34412f7e3d Whitespace tokens are not skipped
Differentiate single quoted string and double quoted string
2018-09-26 22:46:16 +08:00
Jovansonlee Cesar
8dbb62cddd unify parsing of sql_values 2018-09-26 15:41:57 +08:00
Jovansonlee Cesar
6aca4de658 Remove unused functions 2018-09-26 15:11:49 +08:00
Jovansonlee Cesar
096b2bf7ba Parsing timestamp and datetime alongside 2018-09-26 14:56:46 +08:00
Jovansonlee Cesar
7803063ece Add parsing of timestamp values 2018-09-25 22:33:01 +08:00
Jovansonlee Cesar
9ab5c1358d Modularize SQLValue into an enum
Add capability of parsing dates
2018-09-25 15:54:29 +08:00
Jovansonlee Cesar
199ec67da7 Add implementation for parsing SQL COPY 2018-09-25 01:31:54 +08:00
Jovansonlee Cesar
719df789e4 Merging parse_inser and improve-create-table branch into these 2018-09-24 19:14:26 +08:00
Jovansonlee Cesar
78c054ea19 Add Boolean value data type
remove unecessary consume of LParen and RParen in default value
2018-09-24 05:53:58 +08:00
Jovansonlee Cesar
2007995938 Improve the create statement parser that uses create statements from pg database dump
Added PostgreSQL style casting
2018-09-24 03:34:40 +08:00
Jovansonlee Cesar
46274c536b Remove println debugging 2018-09-21 15:37:28 +08:00
Jovansonlee Cesar
5adce6a013 Implement parsing insert statement 2018-09-21 15:19:59 +08:00
Jovansonlee Cesar
7d27abdfb4 Correction on prev_token, the index should decremented 2018-09-21 02:34:44 +08:00
Andy Grove
3fe6fa4041 Reduce duplicate code in tokenizer 2018-09-08 14:55:03 -06:00
Andy Grove
810cd8e6cf tokenizer delegates to dialect now 2018-09-08 14:49:25 -06:00
Andy Grove
96f1f9f35e (cargo-release) start next development iteration 0.1.6-alpha.0 2018-09-08 08:52:10 -06:00
Andy Grove
70f3b78f33 (cargo-release) version 0.1.5 2018-09-08 08:52:01 -06:00
Andy Grove
d5fd4aafaf fix example 2018-09-08 08:51:52 -06:00
Andy Grove
48e78f99dd Update code sample in README 2018-09-08 08:43:15 -06:00
Andy Grove
e16b92763a Update README and description 2018-09-08 08:42:07 -06:00
Andy Grove
06a8870bd7 Introduce concept of dialects 2018-09-08 08:39:32 -06:00
Andy Grove
cc725791de cargo fmt 2018-09-08 08:10:05 -06:00
Andy Grove
d58e59324b Add SQLOrderBy struct to replace ASTNode::OrderByExpr 2018-09-08 08:09:32 -06:00
Andy Grove
e19d559073 Add SQLAssignment struct for use in INSERT 2018-09-08 08:06:10 -06:00
Andy Grove
0d36aa536a Update docs on writing custom parsers 2018-09-08 07:29:34 -06:00
Andy Grove
6374b521c9 Update documentation to point to docs.rs 2018-09-08 07:29:17 -06:00
Andy Grove
049fe9034f (cargo-release) start next development iteration 0.1.5-alpha.0 2018-09-08 07:24:40 -06:00
125 changed files with 98858 additions and 1728 deletions

38
.asf.yaml Normal file
View file

@ -0,0 +1,38 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# This file controls the settings of this repository
#
# See more details at
# https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features
notifications:
commits: commits@datafusion.apache.org
issues: github@datafusion.apache.org
pullrequests: github@datafusion.apache.org
github:
description: "Extensible SQL Lexer and Parser for Rust"
labels:
- big-data
- rust
- sql
enabled_merge_buttons:
squash: true
merge: false
rebase: false
features:
issues: true

View file

@ -0,0 +1,42 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Prepare Rust Builder
description: 'Prepare Rust Build Environment'
inputs:
rust-version:
description: 'version of rust to install (e.g. stable)'
required: true
default: 'stable'
targets:
description: 'The toolchain targets to add, comma-separated'
default: ''
runs:
using: "composite"
steps:
- name: Setup Rust Toolchain
shell: bash
run: |
echo "Installing ${{ inputs.rust-version }}"
if [ -n "${{ inputs.targets}}" ]; then
rustup toolchain install ${{ inputs.rust-version }} -t ${{ inputs.targets }}
else
rustup toolchain install ${{ inputs.rust-version }}
fi
rustup default ${{ inputs.rust-version }}
rustup component add rustfmt clippy

29
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: cargo
directory: "/sqlparser_bench"
schedule:
interval: daily
open-pull-requests-limit: 10

39
.github/workflows/license.yml vendored Normal file
View file

@ -0,0 +1,39 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: license
# trigger for all PRs and changes to main
on:
push:
branches:
- main
pull_request:
jobs:
rat:
name: Release Audit Tool (RAT)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: 3.8
- name: Audit licenses
run: ./dev/release/run-rat.sh .

95
.github/workflows/rust.yml vendored Normal file
View file

@ -0,0 +1,95 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Rust
on: [push, pull_request]
permissions:
contents: read
jobs:
codestyle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
- run: cargo fmt --all -- --check
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
- run: cargo clippy --all-targets --all-features -- -D warnings
benchmark-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
- run: cd sqlparser_bench && cargo clippy --all-targets --all-features -- -D warnings
compile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
- run: cargo check --all-targets --all-features
docs:
runs-on: ubuntu-latest
env:
RUSTDOCFLAGS: "-Dwarnings"
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
- run: cargo doc --document-private-items --no-deps --workspace --all-features
compile-no-std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
with:
targets: 'thumbv6m-none-eabi'
- run: cargo check --no-default-features --target thumbv6m-none-eabi
test:
strategy:
matrix:
rust: [stable, beta, nightly]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Rust Toolchain
uses: ./.github/actions/setup-builder
with:
rust-version: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
- name: Install Tarpaulin
run: cargo install cargo-tarpaulin
- name: Test
run: cargo test --all-features

38
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,38 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: "Close stale PRs"
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-stale-prs:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
stale-pr-message: "Thank you for your contribution. Unfortunately, this pull request is stale because it has been open 60 days with no activity. Please remove the stale label or comment or this will be closed in 7 days."
days-before-pr-stale: 60
days-before-pr-close: 7
# do not close stale issues
days-before-issue-stale: -1
days-before-issue-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

8
.gitignore vendored
View file

@ -1,6 +1,9 @@
# Generated by Cargo
# will have compiled files and executables
/target/
/sqlparser_bench/target/
/derive/target/
dev/dist
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
@ -11,3 +14,8 @@ Cargo.lock
# IDEs
.idea
.vscode
*.swp
.DS_store

1
.tool-versions Normal file
View file

@ -0,0 +1 @@
rust 1.75.0

View file

@ -1,32 +0,0 @@
dist: trusty
sudo: required
cache: cargo
language: rust
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- binutils-dev
- cmake
sources:
- kalakris-cmake
rust:
- nightly
before_script:
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
- cargo install --force cargo-travis && export PATH=$HOME/.cargo/bin:$PATH
script:
- travis-cargo build
- travis-cargo test
after_success:
- cargo coveralls --verbose
env:
global:
- TRAVIS_CARGO_NIGHTLY_FEATURE=""

36
CHANGELOG.md Normal file
View file

@ -0,0 +1,36 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Changelog
All notable changes to this project will be documented in one of the linked
files.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Given that the parser produces a typed AST, any changes to the AST will
technically be breaking and thus will result in a `0.(N+1)` version.
- Unreleased: Check https://github.com/sqlparser-rs/sqlparser-rs/commits/main for undocumented changes.
- `0.56.0`: [changelog/0.56.0.md](changelog/0.56.0.md)
- `0.55.0`: [changelog/0.55.0.md](changelog/0.55.0.md)
- `0.54.0`: [changelog/0.54.0.md](changelog/0.54.0.md)
- `0.53.0`: [changelog/0.53.0.md](changelog/0.53.0.md)
- `0.52.0`: [changelog/0.52.0.md](changelog/0.52.0.md)
- `0.51.0` and earlier: [changelog/0.51.0-pre.md](changelog/0.51.0-pre.md)

View file

@ -1,22 +1,66 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
[package]
name = "sqlparser"
description = "ANSI SQL parser"
version = "0.1.4"
authors = ["Andy Grove <andygrove73@gmail.com>"]
homepage = "https://github.com/andygrove/sqlparser-rs"
documentation = "https://github.com/andygrove/sqlparser-rs"
keywords = [ "sql", "lexer", "parser" ]
repository = "https://github.com/andygrove/sqlparser-rs"
description = "Extensible SQL Lexer and Parser with support for ANSI SQL:2011"
version = "0.57.0"
authors = ["Apache DataFusion <dev@datafusion.apache.org>"]
homepage = "https://github.com/apache/datafusion-sqlparser-rs"
documentation = "https://docs.rs/sqlparser/"
keywords = ["ansi", "sql", "lexer", "parser"]
repository = "https://github.com/apache/datafusion-sqlparser-rs"
license = "Apache-2.0"
include = [
"src/**/*.rs",
"Cargo.toml",
"LICENSE.TXT",
]
edition = "2021"
[lib]
name = "sqlparser"
path = "src/lib.rs"
[features]
default = ["std", "recursive-protection"]
std = []
recursive-protection = ["std", "recursive"]
# Enable JSON output in the `cli` example:
json_example = ["serde_json", "serde"]
visitor = ["sqlparser_derive"]
[dependencies]
fnv = "1.0.3"
lazy_static = "1.0"
bigdecimal = { version = "0.4.1", features = ["serde"], optional = true }
log = "0.4"
recursive = { version = "0.1.1", optional = true}
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"], optional = true }
# serde_json is only used in examples/cli, but we have to put it outside
# of dev-dependencies because of
# https://github.com/rust-lang/cargo/issues/1596
serde_json = { version = "1.0", optional = true }
sqlparser_derive = { version = "0.3.0", path = "derive", optional = true }
[dev-dependencies]
simple_logger = "5.0"
matches = "0.1"
pretty_assertions = "1"
[package.metadata.docs.rs]
# Document these features on docs.rs
features = ["serde", "visitor"]

16
HEADER Normal file
View file

@ -0,0 +1,16 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

277
README.md
View file

@ -1,28 +1,51 @@
# ANSI SQL Lexer and Parser for Rust
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Extensible SQL Lexer and Parser for Rust
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Version](https://img.shields.io/crates/v/sqlparser.svg)](https://crates.io/crates/sqlparser)
[![Build Status](https://travis-ci.org/andygrove/sqlparser-rs.svg?branch=master)](https://travis-ci.org/andygrove/sqlparser-rs)
[![Coverage Status](https://coveralls.io/repos/github/andygrove/sqlparser-rs/badge.svg?branch=master)](https://coveralls.io/github/andygrove/sqlparser-rs?branch=master)
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/datafusion-rs)
[![Build Status](https://github.com/sqlparser-rs/sqlparser-rs/workflows/Rust/badge.svg?branch=main)](https://github.com/sqlparser-rs/sqlparser-rs/actions?query=workflow%3ARust+branch%3Amain)
[![Coverage Status](https://coveralls.io/repos/github/sqlparser-rs/sqlparser-rs/badge.svg?branch=main)](https://coveralls.io/github/sqlparser-rs/sqlparser-rs?branch=main)
[![Gitter Chat](https://badges.gitter.im/sqlparser-rs/community.svg)](https://gitter.im/sqlparser-rs/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The primary goal of this project is to build a SQL lexer and parser capable of parsing SQL that conforms with the [ANSI SQL:2011](https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#_5_1_sql_terminal_character) standard.
A secondary goal is to make it easy for others to use this library as a foundation for building custom SQL parsers for vendor-specific dialects.
This parser is currently being used by the [DataFusion](https://github.com/datafusion-rs/datafusion) query engine.
This crate contains a lexer and parser for SQL that conforms with the
[ANSI/ISO SQL standard][sql-standard] and other dialects. This crate
is used as a foundation for SQL query engines, vendor-specific
parsers, and various SQL analysis.
## Example
The current code is capable of parsing some trivial SELECT and CREATE TABLE statements.
To parse a simple `SELECT` statement:
```rust
let sql = "SELECT a, b, 123, myfunc(b) \
FROM table_1 \
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
let ast = Parser::parse_sql(sql.to_string()).unwrap();
let sql = "SELECT a, b, 123, myfunc(b) \
FROM table_1 \
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";
let dialect = GenericDialect {}; // or AnsiDialect, or your own dialect ...
let ast = Parser::parse_sql(&dialect, sql).unwrap();
println!("AST: {:?}", ast);
```
@ -30,24 +53,232 @@ println!("AST: {:?}", ast);
This outputs
```rust
AST: SQLSelect { projection: [SQLIdentifier("a"), SQLIdentifier("b"), SQLLiteralLong(123), SQLFunction { id: "myfunc", args: [SQLIdentifier("b")] }], relation: Some(SQLIdentifier("table_1")), selection: Some(SQLBinaryExpr { left: SQLBinaryExpr { left: SQLIdentifier("a"), op: Gt, right: SQLIdentifier("b") }, op: And, right: SQLBinaryExpr { left: SQLIdentifier("b"), op: Lt, right: SQLLiteralLong(100) } }), order_by: Some([SQLOrderBy { expr: SQLIdentifier("a"), asc: false }, SQLOrderBy { expr: SQLIdentifier("b"), asc: true }]), group_by: None, having: None, limit: None }
AST: [Query(Query { ctes: [], body: Select(Select { distinct: false, projection: [UnnamedExpr(Identifier("a")), UnnamedExpr(Identifier("b")), UnnamedExpr(Value(Long(123))), UnnamedExpr(Function(Function { name:ObjectName([Identifier(Ident { value: "myfunc", quote_style: None })]), args: [Identifier("b")], filter: None, over: None, distinct: false }))], from: [TableWithJoins { relation: Table { name: ObjectName([Identifier(Ident { value: "table_1", quote_style: None })]), alias: None, args: [], with_hints: [] }, joins: [] }], selection: Some(BinaryOp { left: BinaryOp { left: Identifier("a"), op: Gt, right: Identifier("b") }, op: And, right: BinaryOp { left: Identifier("b"), op: Lt, right: Value(Long(100)) } }), group_by: [], having: None }), order_by: [OrderByExpr { expr: Identifier("a"), asc: Some(false) }, OrderByExpr { expr: Identifier("b"), asc: None }], limit: None, offset: None, fetch: None })]
```
## Features
The following optional [crate features](https://doc.rust-lang.org/cargo/reference/features.html) are available:
* `serde`: Adds [Serde](https://serde.rs/) support by implementing `Serialize` and `Deserialize` for all AST nodes.
* `visitor`: Adds a `Visitor` capable of recursively walking the AST tree.
* `recursive-protection` (enabled by default), uses [recursive](https://docs.rs/recursive/latest/recursive/) for stack overflow protection.
## Syntax vs Semantics
This crate provides only a syntax parser, and tries to avoid applying
any SQL semantics, and accepts queries that specific databases would
reject, even when using that Database's specific `Dialect`. For
example, `CREATE TABLE(x int, x int)` is accepted by this crate, even
though most SQL engines will reject this statement due to the repeated
column name `x`.
This crate avoids semantic analysis because it varies drastically
between dialects and implementations. If you want to do semantic
analysis, feel free to use this project as a base.
## Preserves Syntax Round Trip
This crate allows users to recover the original SQL text (with comments removed,
normalized whitespace and keyword capitalization), which is useful for tools
that analyze and manipulate SQL.
This means that other than comments, whitespace and the capitalization of
keywords, the following should hold true for all SQL:
```rust
// Parse SQL
let sql = "SELECT 'hello'";
let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
// The original SQL text can be generated from the AST
assert_eq!(ast[0].to_string(), sql);
// The SQL can also be pretty-printed with newlines and indentation
assert_eq!(format!("{:#}", ast[0]), "SELECT\n 'hello'");
```
There are still some cases in this crate where different SQL with seemingly
similar semantics are represented with the same AST. We welcome PRs to fix such
issues and distinguish different syntaxes in the AST.
## Source Locations (Work in Progress)
This crate allows recovering source locations from AST nodes via the [Spanned]
trait, which can be used for advanced diagnostics tooling. Note that this
feature is a work in progress and many nodes report missing or inaccurate spans.
Please see [this ticket] for information on how to contribute missing
improvements.
[Spanned]: https://docs.rs/sqlparser/latest/sqlparser/ast/trait.Spanned.html
[this ticket]: https://github.com/apache/datafusion-sqlparser-rs/issues/1548
```rust
// Parse SQL
let ast = Parser::parse_sql(&GenericDialect, "SELECT A FROM B").unwrap();
// The source span can be retrieved with start and end locations
assert_eq!(ast[0].span(), Span {
start: Location::of(1, 1),
end: Location::of(1, 16),
});
```
## SQL compliance
SQL was first standardized in 1987, and revisions of the standard have been
published regularly since. Most revisions have added significant new features to
the language, and as a result no database claims to support the full breadth of
features. This parser currently supports most of the SQL-92 syntax, plus some
syntax from newer versions that have been explicitly requested, plus various
other dialect-specific syntax. Whenever possible, the [online SQL:2016
grammar][sql-2016-grammar] is used to guide what syntax to accept.
Unfortunately, stating anything more specific about compliance is difficult.
There is no publicly available test suite that can assess compliance
automatically, and doing so manually would strain the project's limited
resources. Still, we are interested in eventually supporting the full SQL
dialect, and we are slowly building out our own test suite.
If you are assessing whether this project will be suitable for your needs,
you'll likely need to experimentally verify whether it supports the subset of
SQL that you need. Please file issues about any unsupported queries that you
discover. Doing so helps us prioritize support for the portions of the standard
that are actually used. Note that if you urgently need support for a feature,
you will likely need to write the implementation yourself. See the
[Contributing](#Contributing) section for details.
## Command line
This crate contains a CLI program that can parse a file and dump the results as JSON:
```
$ cargo run --features json_example --example cli FILENAME.sql [--dialectname]
```
## Users
This parser is currently being used by the [DataFusion] query engine, [LocustDB],
[Ballista], [GlueSQL], [Opteryx], [Polars], [PRQL], [Qrlew], [JumpWire], [ParadeDB], [CipherStash Proxy],
and [GreptimeDB].
If your project is using sqlparser-rs feel free to make a PR to add it
to this list.
## Design
This parser is implemented using the [Pratt Parser](https://tdop.github.io/) design, which is a top-down operator-precedence parser.
The core expression parser uses the [Pratt Parser] design, which is a top-down
operator-precedence (TDOP) parser, while the surrounding SQL statement parser is
a traditional, hand-written recursive descent parser. Eli Bendersky has a good
[tutorial on TDOP parsers][tdop-tutorial], if you are interested in learning
more about the technique.
I am a fan of this design pattern over parser generators for the following reasons:
We are a fan of this design pattern over parser generators for the following
reasons:
- Code is simple to write and can be concise and elegant (this is far from true for this current implementation unfortunately, but I hope to fix that using some macros)
- Code is simple to write and can be concise and elegant
- Performance is generally better than code generated by parser generators
- Debugging is much easier with hand-written code
- It is far easier to extend and make dialect-specific extensions compared to using a parser generator
- It is far easier to extend and make dialect-specific extensions
compared to using a parser generator
## Supporting custom SQL dialects
### Supporting custom SQL dialects
This is a work in progress but I started some notes on [writing a custom SQL parser](docs/custom_sql_parser.md).
This is a work in progress, but we have some notes on [writing a custom SQL
parser](docs/custom_sql_parser.md).
## Contributing
Contributors are welcome! Please see the [current issues](https://github.com/andygrove/sqlparser-rs/issues) and feel free to file more!
Contributions are highly encouraged! However, the bandwidth we have to
maintain this crate is limited. Please read the following sections carefully.
### New Syntax
The most commonly accepted PRs add support for or fix a bug in a feature in the
SQL standard, or a popular RDBMS, such as Microsoft SQL
Server or PostgreSQL, will likely be accepted after a brief
review. Any SQL feature that is dialect specific should be parsed by *both* the relevant [`Dialect`]
as well as [`GenericDialect`].
### Major API Changes
The current maintainers do not plan for any substantial changes to
this crate's API. PRs proposing major refactors
are not likely to be accepted.
### Testing
While we hope to review PRs in a reasonably
timely fashion, it may take a week or more. In order to speed the process,
please make sure the PR passes all CI checks, and includes tests
demonstrating your code works as intended (and to avoid
regressions). Remember to also test error paths.
PRs without tests will not be reviewed or merged. Since the CI
ensures that `cargo test`, `cargo fmt`, and `cargo clippy`, pass you
should likely to run all three commands locally before submitting
your PR.
### Filing Issues
If you are unable to submit a patch, feel free to file an issue instead. Please
try to include:
* some representative examples of the syntax you wish to support or fix;
* the relevant bits of the [SQL grammar][sql-2016-grammar], if the syntax is
part of SQL:2016; and
* links to documentation for the feature for a few of the most popular
databases that support it.
Unfortunately, if you need support for a feature, you will likely need to implement
it yourself, or file a well enough described ticket that another member of the community can do so.
Our goal as maintainers is to facilitate the integration
of various features from various contributors, but not to provide the
implementations ourselves, as we simply don't have the resources.
### Benchmarking
There are several micro benchmarks in the `sqlparser_bench` directory.
You can run them with:
```
git checkout main
cd sqlparser_bench
cargo bench -- --save-baseline main
git checkout <your branch>
cargo bench -- --baseline main
```
By adding the `--save-baseline main` and `--baseline main` you can track the
progress of your improvements as you continue working on the feature branch.
## Licensing
All code in this repository is licensed under the [Apache Software License 2.0](LICENSE.txt).
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
licensed as above, without any additional terms or conditions.
[tdop-tutorial]: https://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing
[`cargo fmt`]: https://github.com/rust-lang/rustfmt#on-the-stable-toolchain
[current issues]: https://github.com/sqlparser-rs/sqlparser-rs/issues
[DataFusion]: https://github.com/apache/arrow-datafusion
[LocustDB]: https://github.com/cswinter/LocustDB
[Ballista]: https://github.com/apache/arrow-ballista
[GlueSQL]: https://github.com/gluesql/gluesql
[Opteryx]: https://github.com/mabel-dev/opteryx
[Polars]: https://pola.rs/
[PRQL]: https://github.com/PRQL/prql
[Qrlew]: https://github.com/Qrlew/qrlew
[JumpWire]: https://github.com/extragoodlabs/jumpwire
[ParadeDB]: https://github.com/paradedb/paradedb
[Pratt Parser]: https://tdop.github.io/
[sql-2016-grammar]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html
[sql-standard]: https://en.wikipedia.org/wiki/ISO/IEC_9075
[`Dialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/trait.Dialect.html
[`GenericDialect`]: https://docs.rs/sqlparser/latest/sqlparser/dialect/struct.GenericDialect.html
[CipherStash Proxy]: https://github.com/cipherstash/proxy
[GreptimeDB]: https://github.com/GreptimeTeam/greptimedb

24
SECURITY.md Normal file
View file

@ -0,0 +1,24 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Security Policy
## Reporting a Vulnerability
Please report security issues to `andrew@nerdnetworks.org`

1188
changelog/0.51.0-pre.md Normal file

File diff suppressed because it is too large Load diff

104
changelog/0.52.0.md Normal file
View file

@ -0,0 +1,104 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.52.0 Changelog
This release consists of 45 commits from 20 contributors. See credits at the end of this changelog for more information.
**Implemented enhancements:**
- feat: support explain options [#1426](https://github.com/apache/datafusion-sqlparser-rs/pull/1426) (kysshsy)
- feat: adding Display implementation to DELETE and INSERT [#1427](https://github.com/apache/datafusion-sqlparser-rs/pull/1427) (seve-martinez)
**Fixed bugs:**
- fix: `maybe_parse` preventing parser from erroring on recursion limit [#1464](https://github.com/apache/datafusion-sqlparser-rs/pull/1464) (tomershaniii)
**Other:**
- Fix parsing of negative values [#1419](https://github.com/apache/datafusion-sqlparser-rs/pull/1419) (agscpp)
- Allow to use ON CLUSTER cluster_name in TRUNCATE syntax [#1428](https://github.com/apache/datafusion-sqlparser-rs/pull/1428) (git-hulk)
- chore: remove redundant punctuation [#1434](https://github.com/apache/datafusion-sqlparser-rs/pull/1434) (Fischer0522)
- MS SQL Server: add support for IDENTITY column option [#1432](https://github.com/apache/datafusion-sqlparser-rs/pull/1432) (7phs)
- Update to ASF header / add when missing [#1437](https://github.com/apache/datafusion-sqlparser-rs/pull/1437) (alamb)
- Some small optimizations [#1424](https://github.com/apache/datafusion-sqlparser-rs/pull/1424) (exrok)
- Fix `codestyle` CI check [#1438](https://github.com/apache/datafusion-sqlparser-rs/pull/1438) (alamb)
- Implements CREATE POLICY syntax for PostgreSQL [#1440](https://github.com/apache/datafusion-sqlparser-rs/pull/1440) (git-hulk)
- make `parse_expr_with_alias` public [#1444](https://github.com/apache/datafusion-sqlparser-rs/pull/1444) (Eason0729)
- Implements DROP POLICY syntax for PostgreSQL [#1445](https://github.com/apache/datafusion-sqlparser-rs/pull/1445) (git-hulk)
- Support `DROP DATABASE` [#1443](https://github.com/apache/datafusion-sqlparser-rs/pull/1443) (linhr)
- Implements ALTER POLICY syntax for PostgreSQL [#1446](https://github.com/apache/datafusion-sqlparser-rs/pull/1446) (git-hulk)
- Add a note discouraging new use of `dialect_of` macro [#1448](https://github.com/apache/datafusion-sqlparser-rs/pull/1448) (alamb)
- Expand handling of `LIMIT 1, 2` handling to include sqlite [#1447](https://github.com/apache/datafusion-sqlparser-rs/pull/1447) (joshuawarner32)
- Fix always uses CommentDef::WithoutEq while parsing the inline comment [#1453](https://github.com/apache/datafusion-sqlparser-rs/pull/1453) (git-hulk)
- Add support for the LIKE ANY and ILIKE ANY pattern-matching condition [#1456](https://github.com/apache/datafusion-sqlparser-rs/pull/1456) (yoavcloud)
- added ability to parse extension to parse_comment inside postgres dialect [#1451](https://github.com/apache/datafusion-sqlparser-rs/pull/1451) (MaxwellKnight)
- Snowflake: support of views column comment [#1441](https://github.com/apache/datafusion-sqlparser-rs/pull/1441) (7phs)
- Add SQLite "ON CONFLICT" column option in CREATE TABLE statements [#1442](https://github.com/apache/datafusion-sqlparser-rs/pull/1442) (nucccc)
- Add support for ASC and DESC in CREATE TABLE column constraints for SQLite. [#1462](https://github.com/apache/datafusion-sqlparser-rs/pull/1462) (caldwell)
- Add support of `EXPLAIN QUERY PLAN` syntax for SQLite dialect [#1458](https://github.com/apache/datafusion-sqlparser-rs/pull/1458) (git-hulk)
- Add "DROP TYPE" support. [#1461](https://github.com/apache/datafusion-sqlparser-rs/pull/1461) (caldwell)
- chore: Add asf.yaml [#1463](https://github.com/apache/datafusion-sqlparser-rs/pull/1463) (Xuanwo)
- Add support for quantified comparison predicates (ALL/ANY/SOME) [#1459](https://github.com/apache/datafusion-sqlparser-rs/pull/1459) (yoavcloud)
- MySQL dialect: Add support for hash comments [#1466](https://github.com/apache/datafusion-sqlparser-rs/pull/1466) (hansott)
- Fix #1469 (SET ROLE regression) [#1474](https://github.com/apache/datafusion-sqlparser-rs/pull/1474) (lovasoa)
- Add support for parsing MsSql alias with equals [#1467](https://github.com/apache/datafusion-sqlparser-rs/pull/1467) (yoavcloud)
- Snowflake: support for extended column options in `CREATE TABLE` [#1454](https://github.com/apache/datafusion-sqlparser-rs/pull/1454) (7phs)
- MsSQL TRY_CONVERT [#1477](https://github.com/apache/datafusion-sqlparser-rs/pull/1477) (yoavcloud)
- Add PostgreSQL specfic "CREATE TYPE t AS ENUM (...)" support. [#1460](https://github.com/apache/datafusion-sqlparser-rs/pull/1460) (caldwell)
- Fix build [#1483](https://github.com/apache/datafusion-sqlparser-rs/pull/1483) (yoavcloud)
- Fix complex blocks warning when running clippy [#1488](https://github.com/apache/datafusion-sqlparser-rs/pull/1488) (git-hulk)
- Add support for SHOW DATABASES/SCHEMAS/TABLES/VIEWS in Hive [#1487](https://github.com/apache/datafusion-sqlparser-rs/pull/1487) (yoavcloud)
- Fix typo in `Dialect::supports_eq_alias_assigment` [#1478](https://github.com/apache/datafusion-sqlparser-rs/pull/1478) (alamb)
- Add support for PostgreSQL `LISTEN/NOTIFY` syntax [#1485](https://github.com/apache/datafusion-sqlparser-rs/pull/1485) (wugeer)
- Add support for TOP before ALL/DISTINCT [#1495](https://github.com/apache/datafusion-sqlparser-rs/pull/1495) (yoavcloud)
- add support for `FOR ORDINALITY` and `NESTED` in JSON_TABLE [#1493](https://github.com/apache/datafusion-sqlparser-rs/pull/1493) (lovasoa)
- Add Apache License to additional files [#1502](https://github.com/apache/datafusion-sqlparser-rs/pull/1502) (alamb)
- Move CHANGELOG content [#1503](https://github.com/apache/datafusion-sqlparser-rs/pull/1503) (alamb)
- improve support for T-SQL EXECUTE statements [#1490](https://github.com/apache/datafusion-sqlparser-rs/pull/1490) (lovasoa)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
8 Andrew Lamb
7 Yoav Cohen
7 hulk
3 Aleksei Piianin
3 David Caldwell
3 Ophir LOJKINE
1 Agaev Guseyn
1 Eason
1 Fischer
1 Hans Ott
1 Heran Lin
1 Joshua Warner
1 Maxwell Knight
1 Seve Martinez
1 Siyuan Huang
1 Thomas Dagenais
1 Xuanwo
1 nucccc
1 tomershaniii
1 wugeer
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

95
changelog/0.53.0.md Normal file
View file

@ -0,0 +1,95 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.53.0 Changelog
This release consists of 47 commits from 16 contributors. See credits at the end of this changelog for more information.
**Other:**
- hive: support for special not expression `!a` and raise error for `a!` factorial operator [#1472](https://github.com/apache/datafusion-sqlparser-rs/pull/1472) (wugeer)
- Add support for MSSQL's `OPENJSON WITH` clause [#1498](https://github.com/apache/datafusion-sqlparser-rs/pull/1498) (gaoqiangz)
- Parse true and false as identifiers in mssql [#1510](https://github.com/apache/datafusion-sqlparser-rs/pull/1510) (lovasoa)
- Fix the parsing error in MSSQL for multiple statements that include `DECLARE` statements [#1497](https://github.com/apache/datafusion-sqlparser-rs/pull/1497) (wugeer)
- Add support for Snowflake SHOW DATABASES/SCHEMAS/TABLES/VIEWS/COLUMNS statements [#1501](https://github.com/apache/datafusion-sqlparser-rs/pull/1501) (yoavcloud)
- Add support of COMMENT ON syntax for Snowflake [#1516](https://github.com/apache/datafusion-sqlparser-rs/pull/1516) (git-hulk)
- Add support for MYSQL's `CREATE TABLE SELECT` expr [#1515](https://github.com/apache/datafusion-sqlparser-rs/pull/1515) (wugeer)
- Add support for MSSQL's `XQuery` methods [#1500](https://github.com/apache/datafusion-sqlparser-rs/pull/1500) (gaoqiangz)
- Add support for Hive's `LOAD DATA` expr [#1520](https://github.com/apache/datafusion-sqlparser-rs/pull/1520) (wugeer)
- Fix ClickHouse document link from `Russian` to `English` [#1527](https://github.com/apache/datafusion-sqlparser-rs/pull/1527) (git-hulk)
- Support ANTI and SEMI joins without LEFT/RIGHT [#1528](https://github.com/apache/datafusion-sqlparser-rs/pull/1528) (delamarch3)
- support sqlite's OR clauses in update statements [#1530](https://github.com/apache/datafusion-sqlparser-rs/pull/1530) (lovasoa)
- support column type definitions in table aliases [#1526](https://github.com/apache/datafusion-sqlparser-rs/pull/1526) (lovasoa)
- Add support for MSSQL's `JSON_ARRAY`/`JSON_OBJECT` expr [#1507](https://github.com/apache/datafusion-sqlparser-rs/pull/1507) (gaoqiangz)
- Add support for PostgreSQL `UNLISTEN` syntax and Add support for Postgres `LOAD extension` expr [#1531](https://github.com/apache/datafusion-sqlparser-rs/pull/1531) (wugeer)
- Parse byte/bit string literals in MySQL and Postgres [#1532](https://github.com/apache/datafusion-sqlparser-rs/pull/1532) (mvzink)
- Allow example CLI to read from stdin [#1536](https://github.com/apache/datafusion-sqlparser-rs/pull/1536) (mvzink)
- recursive select calls are parsed with bad trailing_commas parameter [#1521](https://github.com/apache/datafusion-sqlparser-rs/pull/1521) (tomershaniii)
- PartiQL queries in Redshift [#1534](https://github.com/apache/datafusion-sqlparser-rs/pull/1534) (yoavcloud)
- Include license file in sqlparser_derive crate [#1543](https://github.com/apache/datafusion-sqlparser-rs/pull/1543) (ankane)
- Fallback to identifier parsing if expression parsing fails [#1513](https://github.com/apache/datafusion-sqlparser-rs/pull/1513) (yoavcloud)
- support `json_object('k':'v')` in postgres [#1546](https://github.com/apache/datafusion-sqlparser-rs/pull/1546) (lovasoa)
- Document micro benchmarks [#1555](https://github.com/apache/datafusion-sqlparser-rs/pull/1555) (alamb)
- Implement `Spanned` to retrieve source locations on AST nodes [#1435](https://github.com/apache/datafusion-sqlparser-rs/pull/1435) (Nyrox)
- Fix error in benchmark queries [#1560](https://github.com/apache/datafusion-sqlparser-rs/pull/1560) (alamb)
- Fix clippy warnings on rust 1.83 [#1570](https://github.com/apache/datafusion-sqlparser-rs/pull/1570) (iffyio)
- Support relation visitor to visit the `Option` field [#1556](https://github.com/apache/datafusion-sqlparser-rs/pull/1556) (goldmedal)
- Rename `TokenWithLocation` to `TokenWithSpan`, in backwards compatible way [#1562](https://github.com/apache/datafusion-sqlparser-rs/pull/1562) (alamb)
- Support MySQL size variants for BLOB and TEXT columns [#1564](https://github.com/apache/datafusion-sqlparser-rs/pull/1564) (mvzink)
- Increase version of sqlparser_derive from 0.2.2 to 0.3.0 [#1571](https://github.com/apache/datafusion-sqlparser-rs/pull/1571) (alamb)
- `json_object('k' VALUE 'v')` in postgres [#1547](https://github.com/apache/datafusion-sqlparser-rs/pull/1547) (lovasoa)
- Support snowflake double dot notation for object name [#1540](https://github.com/apache/datafusion-sqlparser-rs/pull/1540) (ayman-sigma)
- Update comments / docs for `Spanned` [#1549](https://github.com/apache/datafusion-sqlparser-rs/pull/1549) (alamb)
- Support Databricks struct literal [#1542](https://github.com/apache/datafusion-sqlparser-rs/pull/1542) (ayman-sigma)
- Encapsulate CreateFunction [#1573](https://github.com/apache/datafusion-sqlparser-rs/pull/1573) (philipcristiano)
- Support BIT column types [#1577](https://github.com/apache/datafusion-sqlparser-rs/pull/1577) (mvzink)
- Support parsing optional nulls handling for unique constraint [#1567](https://github.com/apache/datafusion-sqlparser-rs/pull/1567) (mvzink)
- Fix displaying WORK or TRANSACTION after BEGIN [#1565](https://github.com/apache/datafusion-sqlparser-rs/pull/1565) (mvzink)
- Add support of the ENUM8|ENUM16 for ClickHouse dialect [#1574](https://github.com/apache/datafusion-sqlparser-rs/pull/1574) (git-hulk)
- Parse Snowflake USE ROLE and USE SECONDARY ROLES [#1578](https://github.com/apache/datafusion-sqlparser-rs/pull/1578) (yoavcloud)
- Snowflake ALTER TABLE clustering options [#1579](https://github.com/apache/datafusion-sqlparser-rs/pull/1579) (yoavcloud)
- Support INSERT OVERWRITE INTO syntax [#1584](https://github.com/apache/datafusion-sqlparser-rs/pull/1584) (yuval-illumex)
- Parse `INSERT` with subquery when lacking column names [#1586](https://github.com/apache/datafusion-sqlparser-rs/pull/1586) (iffyio)
- Add support for ODBC functions [#1585](https://github.com/apache/datafusion-sqlparser-rs/pull/1585) (iffyio)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
8 Andrew Lamb
6 Michael Victor Zink
5 Ophir LOJKINE
5 Yoav Cohen
5 wugeer
3 Ifeanyi Ubah
3 gaoqiangz
3 hulk
2 Ayman Elkfrawy
1 Andrew Kane
1 Jax Liu
1 Mark-Oliver Junge
1 Philip Cristiano
1 Yuval Shkolar
1 delamarch3
1 tomershaniii
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

118
changelog/0.54.0.md Normal file
View file

@ -0,0 +1,118 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.54.0 Changelog
This release consists of 57 commits from 24 contributors. See credits at the end of this changelog for more information.
**Implemented enhancements:**
- feat: support `INSERT INTO [TABLE] FUNCTION` of Clickhouse [#1633](https://github.com/apache/datafusion-sqlparser-rs/pull/1633) (byte-sourcerer)
**Other:**
- Run cargo fmt on `derive` crate [#1595](https://github.com/apache/datafusion-sqlparser-rs/pull/1595) (alamb)
- Add Apache license header to spans.rs [#1594](https://github.com/apache/datafusion-sqlparser-rs/pull/1594) (alamb)
- Add support for BigQuery `ANY TYPE` data type [#1602](https://github.com/apache/datafusion-sqlparser-rs/pull/1602) (MartinSahlen)
- Add support for TABLESAMPLE [#1580](https://github.com/apache/datafusion-sqlparser-rs/pull/1580) (yoavcloud)
- Redshift: Fix parsing for quoted numbered columns [#1576](https://github.com/apache/datafusion-sqlparser-rs/pull/1576) (7phs)
- Add the alter table ON COMMIT option to Snowflake [#1606](https://github.com/apache/datafusion-sqlparser-rs/pull/1606) (yoavcloud)
- Support parsing `EXPLAIN ESTIMATE` of Clickhouse [#1605](https://github.com/apache/datafusion-sqlparser-rs/pull/1605) (byte-sourcerer)
- Fix BigQuery hyphenated ObjectName with numbers [#1598](https://github.com/apache/datafusion-sqlparser-rs/pull/1598) (ayman-sigma)
- Fix test compilation issue [#1609](https://github.com/apache/datafusion-sqlparser-rs/pull/1609) (iffyio)
- Allow foreign table constraint without columns [#1608](https://github.com/apache/datafusion-sqlparser-rs/pull/1608) (ramnivas)
- Support optional table for `ANALYZE` statement [#1599](https://github.com/apache/datafusion-sqlparser-rs/pull/1599) (yuyang-ok)
- Support DOUBLE data types with precision for Mysql [#1611](https://github.com/apache/datafusion-sqlparser-rs/pull/1611) (artorias1024)
- Add `#[recursive]` [#1522](https://github.com/apache/datafusion-sqlparser-rs/pull/1522) (blaginin)
- Support arbitrary composite access expressions [#1600](https://github.com/apache/datafusion-sqlparser-rs/pull/1600) (ayman-sigma)
- Consolidate `MapAccess`, and `Subscript` into `CompoundExpr` to handle the complex field access chain [#1551](https://github.com/apache/datafusion-sqlparser-rs/pull/1551) (goldmedal)
- Handle empty projection in Postgres SELECT statements [#1613](https://github.com/apache/datafusion-sqlparser-rs/pull/1613) (tobyhede)
- Merge composite and compound expr test cases [#1615](https://github.com/apache/datafusion-sqlparser-rs/pull/1615) (iffyio)
- Support Snowflake Update-From-Select [#1604](https://github.com/apache/datafusion-sqlparser-rs/pull/1604) (yuval-illumex)
- Improve parsing performance by reducing token cloning [#1587](https://github.com/apache/datafusion-sqlparser-rs/pull/1587) (davisp)
- Improve Parser documentation [#1617](https://github.com/apache/datafusion-sqlparser-rs/pull/1617) (alamb)
- Add support for DROP EXTENSION [#1610](https://github.com/apache/datafusion-sqlparser-rs/pull/1610) (ramnivas)
- Refactor advancing token to avoid duplication, avoid borrow checker issues [#1618](https://github.com/apache/datafusion-sqlparser-rs/pull/1618) (alamb)
- Fix the parsing result for the special double number [#1621](https://github.com/apache/datafusion-sqlparser-rs/pull/1621) (goldmedal)
- SQLite: Allow dollar signs in placeholder names [#1620](https://github.com/apache/datafusion-sqlparser-rs/pull/1620) (hansott)
- Improve error for an unexpected token after DROP [#1623](https://github.com/apache/datafusion-sqlparser-rs/pull/1623) (ramnivas)
- Fix `sqlparser_bench` benchmark compilation [#1625](https://github.com/apache/datafusion-sqlparser-rs/pull/1625) (alamb)
- Improve parsing speed by avoiding some clones in parse_identifier [#1624](https://github.com/apache/datafusion-sqlparser-rs/pull/1624) (alamb)
- Simplify `parse_keyword_apis` more [#1626](https://github.com/apache/datafusion-sqlparser-rs/pull/1626) (alamb)
- Test benchmarks and Improve benchmark README.md [#1627](https://github.com/apache/datafusion-sqlparser-rs/pull/1627) (alamb)
- Add support for MYSQL's `RENAME TABLE` [#1616](https://github.com/apache/datafusion-sqlparser-rs/pull/1616) (wugeer)
- Correctly tokenize nested comments [#1629](https://github.com/apache/datafusion-sqlparser-rs/pull/1629) (hansott)
- Add support for USE SECONDARY ROLE (vs. ROLES) [#1637](https://github.com/apache/datafusion-sqlparser-rs/pull/1637) (yoavcloud)
- Add support for various Snowflake grantees [#1640](https://github.com/apache/datafusion-sqlparser-rs/pull/1640) (yoavcloud)
- Add support for the SQL OVERLAPS predicate [#1638](https://github.com/apache/datafusion-sqlparser-rs/pull/1638) (yoavcloud)
- Add support for Snowflake LIST and REMOVE [#1639](https://github.com/apache/datafusion-sqlparser-rs/pull/1639) (yoavcloud)
- Add support for MySQL's INSERT INTO ... SET syntax [#1641](https://github.com/apache/datafusion-sqlparser-rs/pull/1641) (yoavcloud)
- Start new line if \r in Postgres dialect [#1647](https://github.com/apache/datafusion-sqlparser-rs/pull/1647) (hansott)
- Support pluralized time units [#1630](https://github.com/apache/datafusion-sqlparser-rs/pull/1630) (wugeer)
- Replace `ReferentialAction` enum in `DROP` statements [#1648](https://github.com/apache/datafusion-sqlparser-rs/pull/1648) (stepancheg)
- Add support for MS-SQL BEGIN/END TRY/CATCH [#1649](https://github.com/apache/datafusion-sqlparser-rs/pull/1649) (yoavcloud)
- Fix MySQL parsing of GRANT, REVOKE, and CREATE VIEW [#1538](https://github.com/apache/datafusion-sqlparser-rs/pull/1538) (mvzink)
- Add support for the Snowflake MINUS set operator [#1652](https://github.com/apache/datafusion-sqlparser-rs/pull/1652) (yoavcloud)
- ALTER TABLE DROP {COLUMN|CONSTRAINT} RESTRICT [#1651](https://github.com/apache/datafusion-sqlparser-rs/pull/1651) (stepancheg)
- Add support for ClickHouse `FORMAT` on `INSERT` [#1628](https://github.com/apache/datafusion-sqlparser-rs/pull/1628) (bombsimon)
- MsSQL SET for session params [#1646](https://github.com/apache/datafusion-sqlparser-rs/pull/1646) (yoavcloud)
- Correctly look for end delimiter dollar quoted string [#1650](https://github.com/apache/datafusion-sqlparser-rs/pull/1650) (hansott)
- Support single line comments starting with '#' for Hive [#1654](https://github.com/apache/datafusion-sqlparser-rs/pull/1654) (wugeer)
- Support trailing commas in `FROM` clause [#1645](https://github.com/apache/datafusion-sqlparser-rs/pull/1645) (barsela1)
- Allow empty options for BigQuery [#1657](https://github.com/apache/datafusion-sqlparser-rs/pull/1657) (MartinSahlen)
- Add support for parsing RAISERROR [#1656](https://github.com/apache/datafusion-sqlparser-rs/pull/1656) (AvivDavid-Satori)
- Add support for Snowflake column aliases that use SQL keywords [#1632](https://github.com/apache/datafusion-sqlparser-rs/pull/1632) (yoavcloud)
- fix parsing of `INSERT INTO ... SELECT ... RETURNING ` [#1661](https://github.com/apache/datafusion-sqlparser-rs/pull/1661) (lovasoa)
- Add support for `IS [NOT] [form] NORMALIZED` [#1655](https://github.com/apache/datafusion-sqlparser-rs/pull/1655) (alexander-beedie)
- Add support for qualified column names in JOIN ... USING [#1663](https://github.com/apache/datafusion-sqlparser-rs/pull/1663) (yoavcloud)
- Add support for Snowflake AT/BEFORE [#1667](https://github.com/apache/datafusion-sqlparser-rs/pull/1667) (yoavcloud)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
13 Yoav Cohen
9 Andrew Lamb
4 Hans Ott
3 Ramnivas Laddad
3 wugeer
2 Ayman Elkfrawy
2 Ifeanyi Ubah
2 Jax Liu
2 Martin Abelson Sahlen
2 Stepan Koltsov
2 cjw
1 Aleksei Piianin
1 Alexander Beedie
1 AvivDavid-Satori
1 Dmitrii Blaginin
1 Michael Victor Zink
1 Ophir LOJKINE
1 Paul J. Davis
1 Simon Sawert
1 Toby Hede
1 Yuval Shkolar
1 artorias1024
1 bar sela
1 yuyang
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

173
changelog/0.55.0.md Normal file
View file

@ -0,0 +1,173 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.55.0 Changelog
This release consists of 55 commits from 25 contributors. See credits at the end of this changelog for more information.
## Migrating usages of `Expr::Value`
In v0.55 of sqlparser the `Expr::Value` enum variant contains a `ValueWithSpan` instead of a `Value`. Here is how to migrate.
### When pattern matching
```diff
- Expr::Value(Value::SingleQuotedString(my_string)) => { ... }
+ Expr::Value(ValueWithSpan{ value: Value::SingleQuotedString(my_string), span: _ }) => { ... }
```
### When creating an `Expr`
Use the new `Expr::value` method (notice the lowercase `v`), which will create a `ValueWithSpan` containing an empty span:
```diff
- Expr::Value(Value::SingleQuotedString(my_string))
+ Expr::value(Value::SingleQuotedString(my_string))
```
## Migrating usages of `ObjectName`
In v0.55 of sqlparser, the `ObjectName` structure has been changed as shown below. Here is now to migrate.
```diff
- pub struct ObjectName(pub Vec<Ident>);
+ pub struct ObjectName(pub Vec<ObjectNamePart>)
```
### When constructing `ObjectName`
Use the `From` impl:
```diff
- name: ObjectName(vec![Ident::new("f")]),
+ name: ObjectName::from(vec![Ident::new("f")]),
```
### Accessing Spans
Use the `span()` function
```diff
- name.span
+ name.span()
```
**Breaking changes:**
- Enhance object name path segments [#1539](https://github.com/apache/datafusion-sqlparser-rs/pull/1539) (ayman-sigma)
- Store spans for Value expressions [#1738](https://github.com/apache/datafusion-sqlparser-rs/pull/1738) (lovasoa)
**Implemented enhancements:**
- feat: adjust create and drop trigger for mysql dialect [#1734](https://github.com/apache/datafusion-sqlparser-rs/pull/1734) (invm)
**Fixed bugs:**
- fix: make `serde` feature no_std [#1730](https://github.com/apache/datafusion-sqlparser-rs/pull/1730) (iajoiner)
**Other:**
- Update rat_exclude_file.txt [#1670](https://github.com/apache/datafusion-sqlparser-rs/pull/1670) (alamb)
- Add support for Snowflake account privileges [#1666](https://github.com/apache/datafusion-sqlparser-rs/pull/1666) (yoavcloud)
- Add support for Create Iceberg Table statement for Snowflake parser [#1664](https://github.com/apache/datafusion-sqlparser-rs/pull/1664) (Vedin)
- National strings: check if dialect supports backslash escape [#1672](https://github.com/apache/datafusion-sqlparser-rs/pull/1672) (hansott)
- Only support escape literals for Postgres, Redshift and generic dialect [#1674](https://github.com/apache/datafusion-sqlparser-rs/pull/1674) (hansott)
- BigQuery: Support trailing commas in column definitions list [#1682](https://github.com/apache/datafusion-sqlparser-rs/pull/1682) (iffyio)
- Enable GROUP BY exp for Snowflake dialect [#1683](https://github.com/apache/datafusion-sqlparser-rs/pull/1683) (yoavcloud)
- Add support for parsing empty dictionary expressions [#1684](https://github.com/apache/datafusion-sqlparser-rs/pull/1684) (yoavcloud)
- Support multiple tables in `UPDATE FROM` clause [#1681](https://github.com/apache/datafusion-sqlparser-rs/pull/1681) (iffyio)
- Add support for mysql table hints [#1675](https://github.com/apache/datafusion-sqlparser-rs/pull/1675) (AvivDavid-Satori)
- BigQuery: Add support for select expr star [#1680](https://github.com/apache/datafusion-sqlparser-rs/pull/1680) (iffyio)
- Support underscore separators in numbers for Clickhouse. Fixes #1659 [#1677](https://github.com/apache/datafusion-sqlparser-rs/pull/1677) (graup)
- BigQuery: Fix column identifier reserved keywords list [#1678](https://github.com/apache/datafusion-sqlparser-rs/pull/1678) (iffyio)
- Fix bug when parsing a Snowflake stage with `;` suffix [#1688](https://github.com/apache/datafusion-sqlparser-rs/pull/1688) (yoavcloud)
- Allow plain JOIN without turning it into INNER [#1692](https://github.com/apache/datafusion-sqlparser-rs/pull/1692) (mvzink)
- Fix DDL generation in case of an empty arguments function. [#1690](https://github.com/apache/datafusion-sqlparser-rs/pull/1690) (remysaissy)
- Fix `CREATE FUNCTION` round trip for Hive dialect [#1693](https://github.com/apache/datafusion-sqlparser-rs/pull/1693) (iffyio)
- Make numeric literal underscore test dialect agnostic [#1685](https://github.com/apache/datafusion-sqlparser-rs/pull/1685) (iffyio)
- Extend lambda support for ClickHouse and DuckDB dialects [#1686](https://github.com/apache/datafusion-sqlparser-rs/pull/1686) (gstvg)
- Make TypedString preserve quote style [#1679](https://github.com/apache/datafusion-sqlparser-rs/pull/1679) (graup)
- Do not parse ASOF and MATCH_CONDITION as table factor aliases [#1698](https://github.com/apache/datafusion-sqlparser-rs/pull/1698) (yoavcloud)
- Add support for GRANT on some common Snowflake objects [#1699](https://github.com/apache/datafusion-sqlparser-rs/pull/1699) (yoavcloud)
- Add RETURNS TABLE() support for CREATE FUNCTION in Postgresql [#1687](https://github.com/apache/datafusion-sqlparser-rs/pull/1687) (remysaissy)
- Add parsing for GRANT ROLE and GRANT DATABASE ROLE in Snowflake dialect [#1689](https://github.com/apache/datafusion-sqlparser-rs/pull/1689) (yoavcloud)
- Add support for `CREATE/ALTER/DROP CONNECTOR` syntax [#1701](https://github.com/apache/datafusion-sqlparser-rs/pull/1701) (wugeer)
- Parse Snowflake COPY INTO <location> [#1669](https://github.com/apache/datafusion-sqlparser-rs/pull/1669) (yoavcloud)
- Require space after -- to start single line comment in MySQL [#1705](https://github.com/apache/datafusion-sqlparser-rs/pull/1705) (hansott)
- Add suppport for Show Objects statement for the Snowflake parser [#1702](https://github.com/apache/datafusion-sqlparser-rs/pull/1702) (DanCodedThis)
- Fix incorrect parsing of JsonAccess bracket notation after cast in Snowflake [#1708](https://github.com/apache/datafusion-sqlparser-rs/pull/1708) (yoavcloud)
- Parse Postgres VARBIT datatype [#1703](https://github.com/apache/datafusion-sqlparser-rs/pull/1703) (mvzink)
- Implement FROM-first selects [#1713](https://github.com/apache/datafusion-sqlparser-rs/pull/1713) (mitsuhiko)
- Enable custom dialects to support `MATCH() AGAINST()` [#1719](https://github.com/apache/datafusion-sqlparser-rs/pull/1719) (joocer)
- Support group by cube/rollup etc in BigQuery [#1720](https://github.com/apache/datafusion-sqlparser-rs/pull/1720) (Groennbeck)
- Add support for MS Varbinary(MAX) (#1714) [#1715](https://github.com/apache/datafusion-sqlparser-rs/pull/1715) (TylerBrinks)
- Add supports for Hive's `SELECT ... GROUP BY .. GROUPING SETS` syntax [#1653](https://github.com/apache/datafusion-sqlparser-rs/pull/1653) (wugeer)
- Differentiate LEFT JOIN from LEFT OUTER JOIN [#1726](https://github.com/apache/datafusion-sqlparser-rs/pull/1726) (mvzink)
- Add support for Postgres `ALTER TYPE` [#1727](https://github.com/apache/datafusion-sqlparser-rs/pull/1727) (jvatic)
- Replace `Method` and `CompositeAccess` with `CompoundFieldAccess` [#1716](https://github.com/apache/datafusion-sqlparser-rs/pull/1716) (iffyio)
- Add support for `EXECUTE IMMEDIATE` [#1717](https://github.com/apache/datafusion-sqlparser-rs/pull/1717) (iffyio)
- Treat COLLATE like any other column option [#1731](https://github.com/apache/datafusion-sqlparser-rs/pull/1731) (mvzink)
- Add support for PostgreSQL/Redshift geometric operators [#1723](https://github.com/apache/datafusion-sqlparser-rs/pull/1723) (benrsatori)
- Implement SnowFlake ALTER SESSION [#1712](https://github.com/apache/datafusion-sqlparser-rs/pull/1712) (osipovartem)
- Extend Visitor trait for Value type [#1725](https://github.com/apache/datafusion-sqlparser-rs/pull/1725) (tomershaniii)
- Add support for `ORDER BY ALL` [#1724](https://github.com/apache/datafusion-sqlparser-rs/pull/1724) (PokIsemaine)
- Parse casting to array using double colon operator in Redshift [#1737](https://github.com/apache/datafusion-sqlparser-rs/pull/1737) (yoavcloud)
- Replace parallel condition/result vectors with single CaseWhen vector in Expr::Case. This fixes the iteration order when using the `Visitor` trait. Expressions are now visited in the same order as they appear in the sql source. [#1733](https://github.com/apache/datafusion-sqlparser-rs/pull/1733) (lovasoa)
- BigQuery: Add support for `BEGIN` [#1718](https://github.com/apache/datafusion-sqlparser-rs/pull/1718) (iffyio)
- Parse SIGNED INTEGER type in MySQL CAST [#1739](https://github.com/apache/datafusion-sqlparser-rs/pull/1739) (mvzink)
- Parse MySQL ALTER TABLE ALGORITHM option [#1745](https://github.com/apache/datafusion-sqlparser-rs/pull/1745) (mvzink)
- Random test cleanups use Expr::value [#1749](https://github.com/apache/datafusion-sqlparser-rs/pull/1749) (alamb)
- Parse ALTER TABLE AUTO_INCREMENT operation for MySQL [#1748](https://github.com/apache/datafusion-sqlparser-rs/pull/1748) (mvzink)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
10 Yoav Cohen
9 Ifeanyi Ubah
7 Michael Victor Zink
3 Hans Ott
2 Andrew Lamb
2 Ophir LOJKINE
2 Paul Grau
2 Rémy SAISSY
2 wugeer
1 Armin Ronacher
1 Artem Osipov
1 AvivDavid-Satori
1 Ayman Elkfrawy
1 DanCodedThis
1 Denys Tsomenko
1 Emil
1 Ian Alexander Joiner
1 Jesse Stuart
1 Justin Joyce
1 Michael
1 SiLe Zhou
1 Tyler Brinks
1 benrsatori
1 gstvg
1 tomershaniii
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

102
changelog/0.56.0.md Normal file
View file

@ -0,0 +1,102 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.56.0 Changelog
This release consists of 48 commits from 19 contributors. See credits at the end of this changelog for more information.
**Other:**
- Ignore escaped LIKE wildcards in MySQL [#1735](https://github.com/apache/datafusion-sqlparser-rs/pull/1735) (mvzink)
- Parse SET NAMES syntax in Postgres [#1752](https://github.com/apache/datafusion-sqlparser-rs/pull/1752) (mvzink)
- re-add support for nested comments in mssql [#1754](https://github.com/apache/datafusion-sqlparser-rs/pull/1754) (lovasoa)
- Extend support for INDEX parsing [#1707](https://github.com/apache/datafusion-sqlparser-rs/pull/1707) (LucaCappelletti94)
- Parse MySQL `ALTER TABLE DROP FOREIGN KEY` syntax [#1762](https://github.com/apache/datafusion-sqlparser-rs/pull/1762) (mvzink)
- add support for `with` clauses (CTEs) in `delete` statements [#1764](https://github.com/apache/datafusion-sqlparser-rs/pull/1764) (lovasoa)
- SET with a list of comma separated assignments [#1757](https://github.com/apache/datafusion-sqlparser-rs/pull/1757) (MohamedAbdeen21)
- Preserve MySQL-style `LIMIT <offset>, <limit>` syntax [#1765](https://github.com/apache/datafusion-sqlparser-rs/pull/1765) (mvzink)
- Add support for `DROP MATERIALIZED VIEW` [#1743](https://github.com/apache/datafusion-sqlparser-rs/pull/1743) (iffyio)
- Add `CASE` and `IF` statement support [#1741](https://github.com/apache/datafusion-sqlparser-rs/pull/1741) (iffyio)
- BigQuery: Add support for `CREATE SCHEMA` options [#1742](https://github.com/apache/datafusion-sqlparser-rs/pull/1742) (iffyio)
- Snowflake: Support dollar quoted comments [#1755](https://github.com/apache/datafusion-sqlparser-rs/pull/1755)
- Add LOCK operation for ALTER TABLE [#1768](https://github.com/apache/datafusion-sqlparser-rs/pull/1768) (MohamedAbdeen21)
- Add support for `RAISE` statement [#1766](https://github.com/apache/datafusion-sqlparser-rs/pull/1766) (iffyio)
- Add GLOBAL context/modifier to SET statements [#1767](https://github.com/apache/datafusion-sqlparser-rs/pull/1767) (MohamedAbdeen21)
- Parse `SUBSTR` as alias for `SUBSTRING` [#1769](https://github.com/apache/datafusion-sqlparser-rs/pull/1769) (mvzink)
- SET statements: scope modifier for multiple assignments [#1772](https://github.com/apache/datafusion-sqlparser-rs/pull/1772) (MohamedAbdeen21)
- Support qualified column names in `MATCH AGAINST` clause [#1774](https://github.com/apache/datafusion-sqlparser-rs/pull/1774) (tomershaniii)
- Mysql: Add support for := operator [#1779](https://github.com/apache/datafusion-sqlparser-rs/pull/1779) (barsela1)
- Add cipherstash-proxy to list of users in README.md [#1782](https://github.com/apache/datafusion-sqlparser-rs/pull/1782) (coderdan)
- Fix typos [#1785](https://github.com/apache/datafusion-sqlparser-rs/pull/1785) (jayvdb)
- Add support for Databricks TIMESTAMP_NTZ. [#1781](https://github.com/apache/datafusion-sqlparser-rs/pull/1781) (romanb)
- Enable double-dot-notation for mssql. [#1787](https://github.com/apache/datafusion-sqlparser-rs/pull/1787) (romanb)
- Fix: Snowflake ALTER SESSION cannot be followed by other statements. [#1786](https://github.com/apache/datafusion-sqlparser-rs/pull/1786) (romanb)
- Add GreptimeDB to the "Users" in README [#1788](https://github.com/apache/datafusion-sqlparser-rs/pull/1788) (MichaelScofield)
- Extend snowflake grant options support [#1794](https://github.com/apache/datafusion-sqlparser-rs/pull/1794) (yoavcloud)
- Fix clippy lint on rust 1.86 [#1796](https://github.com/apache/datafusion-sqlparser-rs/pull/1796) (iffyio)
- Allow single quotes in EXTRACT() for Redshift. [#1795](https://github.com/apache/datafusion-sqlparser-rs/pull/1795) (romanb)
- MSSQL: Add support for functionality `MERGE` output clause [#1790](https://github.com/apache/datafusion-sqlparser-rs/pull/1790) (dilovancelik)
- Support additional DuckDB integer types such as HUGEINT, UHUGEINT, etc [#1797](https://github.com/apache/datafusion-sqlparser-rs/pull/1797) (alexander-beedie)
- Add support for MSSQL IF/ELSE statements. [#1791](https://github.com/apache/datafusion-sqlparser-rs/pull/1791) (romanb)
- Allow literal backslash escapes for string literals in Redshift dialect. [#1801](https://github.com/apache/datafusion-sqlparser-rs/pull/1801) (romanb)
- Add support for MySQL's STRAIGHT_JOIN join operator. [#1802](https://github.com/apache/datafusion-sqlparser-rs/pull/1802) (romanb)
- Snowflake COPY INTO target columns, select items and optional alias [#1805](https://github.com/apache/datafusion-sqlparser-rs/pull/1805) (yoavcloud)
- Fix tokenization of qualified identifiers with numeric prefix. [#1803](https://github.com/apache/datafusion-sqlparser-rs/pull/1803) (romanb)
- Add support for `INHERITS` option in `CREATE TABLE` statement [#1806](https://github.com/apache/datafusion-sqlparser-rs/pull/1806) (LucaCappelletti94)
- Add `DROP TRIGGER` support for SQL Server [#1813](https://github.com/apache/datafusion-sqlparser-rs/pull/1813) (aharpervc)
- Snowflake: support nested join without parentheses [#1799](https://github.com/apache/datafusion-sqlparser-rs/pull/1799) (barsela1)
- Add support for parenthesized subquery as `IN` predicate [#1793](https://github.com/apache/datafusion-sqlparser-rs/pull/1793) (adamchainz)
- Fix `STRAIGHT_JOIN` constraint when table alias is absent [#1812](https://github.com/apache/datafusion-sqlparser-rs/pull/1812) (killertux)
- Add support for `PRINT` statement for SQL Server [#1811](https://github.com/apache/datafusion-sqlparser-rs/pull/1811) (aharpervc)
- enable `supports_filter_during_aggregation` for Generic dialect [#1815](https://github.com/apache/datafusion-sqlparser-rs/pull/1815) (goldmedal)
- Add support for `XMLTABLE` [#1817](https://github.com/apache/datafusion-sqlparser-rs/pull/1817) (lovasoa)
- Add `CREATE FUNCTION` support for SQL Server [#1808](https://github.com/apache/datafusion-sqlparser-rs/pull/1808) (aharpervc)
- Add `OR ALTER` support for `CREATE VIEW` [#1818](https://github.com/apache/datafusion-sqlparser-rs/pull/1818) (aharpervc)
- Add `DECLARE ... CURSOR FOR` support for SQL Server [#1821](https://github.com/apache/datafusion-sqlparser-rs/pull/1821) (aharpervc)
- Handle missing login in changelog generate script [#1823](https://github.com/apache/datafusion-sqlparser-rs/pull/1823) (iffyio)
- Snowflake: Add support for `CONNECT_BY_ROOT` [#1780](https://github.com/apache/datafusion-sqlparser-rs/pull/1780) (tomershaniii)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
8 Roman Borschel
6 Ifeanyi Ubah
5 Andrew Harper
5 Michael Victor Zink
4 Mohamed Abdeen
3 Ophir LOJKINE
2 Luca Cappelletti
2 Yoav Cohen
2 bar sela
2 tomershaniii
1 Adam Johnson
1 Aleksei Piianin
1 Alexander Beedie
1 Bruno Clemente
1 Dan Draper
1 DilovanCelik
1 Jax Liu
1 John Vandenberg
1 LFC
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

95
changelog/0.57.0.md Normal file
View file

@ -0,0 +1,95 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# sqlparser-rs 0.57.0 Changelog
This release consists of 39 commits from 19 contributors. See credits at the end of this changelog for more information.
**Implemented enhancements:**
- feat: Hive: support `SORT BY` direction [#1873](https://github.com/apache/datafusion-sqlparser-rs/pull/1873) (chenkovsky)
**Other:**
- Support some of pipe operators [#1759](https://github.com/apache/datafusion-sqlparser-rs/pull/1759) (simonvandel)
- Added support for `DROP DOMAIN` [#1828](https://github.com/apache/datafusion-sqlparser-rs/pull/1828) (LucaCappelletti94)
- Improve support for cursors for SQL Server [#1831](https://github.com/apache/datafusion-sqlparser-rs/pull/1831) (aharpervc)
- Add all missing table options to be handled in any order [#1747](https://github.com/apache/datafusion-sqlparser-rs/pull/1747) (benrsatori)
- Add `CREATE TRIGGER` support for SQL Server [#1810](https://github.com/apache/datafusion-sqlparser-rs/pull/1810) (aharpervc)
- Added support for `CREATE DOMAIN` [#1830](https://github.com/apache/datafusion-sqlparser-rs/pull/1830) (LucaCappelletti94)
- Allow stored procedures to be defined without `BEGIN`/`END` [#1834](https://github.com/apache/datafusion-sqlparser-rs/pull/1834) (aharpervc)
- Add support for the MATCH and REGEXP binary operators [#1840](https://github.com/apache/datafusion-sqlparser-rs/pull/1840) (lovasoa)
- Fix: parsing ident starting with underscore in certain dialects [#1835](https://github.com/apache/datafusion-sqlparser-rs/pull/1835) (MohamedAbdeen21)
- implement pretty-printing with `{:#}` [#1847](https://github.com/apache/datafusion-sqlparser-rs/pull/1847) (lovasoa)
- Fix big performance issue in string serialization [#1848](https://github.com/apache/datafusion-sqlparser-rs/pull/1848) (lovasoa)
- Add support for `DENY` statements [#1836](https://github.com/apache/datafusion-sqlparser-rs/pull/1836) (aharpervc)
- Postgresql: Add `REPLICA IDENTITY` operation for `ALTER TABLE` [#1844](https://github.com/apache/datafusion-sqlparser-rs/pull/1844) (MohamedAbdeen21)
- Add support for INCLUDE/EXCLUDE NULLS for UNPIVOT [#1849](https://github.com/apache/datafusion-sqlparser-rs/pull/1849) (Vedin)
- pretty print improvements [#1851](https://github.com/apache/datafusion-sqlparser-rs/pull/1851) (lovasoa)
- fix new rust 1.87 cargo clippy warnings [#1856](https://github.com/apache/datafusion-sqlparser-rs/pull/1856) (lovasoa)
- Update criterion requirement from 0.5 to 0.6 in /sqlparser_bench [#1857](https://github.com/apache/datafusion-sqlparser-rs/pull/1857) (dependabot[bot])
- pretty-print CREATE TABLE statements [#1854](https://github.com/apache/datafusion-sqlparser-rs/pull/1854) (lovasoa)
- pretty-print CREATE VIEW statements [#1855](https://github.com/apache/datafusion-sqlparser-rs/pull/1855) (lovasoa)
- Handle optional datatypes properly in `CREATE FUNCTION` statements [#1826](https://github.com/apache/datafusion-sqlparser-rs/pull/1826) (LucaCappelletti94)
- Mysql: Add `SRID` column option [#1852](https://github.com/apache/datafusion-sqlparser-rs/pull/1852) (MohamedAbdeen21)
- Add support for table valued functions for SQL Server [#1839](https://github.com/apache/datafusion-sqlparser-rs/pull/1839) (aharpervc)
- Keep the COLUMN keyword only if it exists when dropping the column [#1862](https://github.com/apache/datafusion-sqlparser-rs/pull/1862) (git-hulk)
- Add support for parameter default values in SQL Server [#1866](https://github.com/apache/datafusion-sqlparser-rs/pull/1866) (aharpervc)
- Add support for `TABLESAMPLE` pipe operator [#1860](https://github.com/apache/datafusion-sqlparser-rs/pull/1860) (hendrikmakait)
- Adds support for mysql's drop index [#1864](https://github.com/apache/datafusion-sqlparser-rs/pull/1864) (dmzmk)
- Fix: GROUPING SETS accept values without parenthesis [#1867](https://github.com/apache/datafusion-sqlparser-rs/pull/1867) (Vedin)
- Add ICEBERG keyword support to ALTER TABLE statement [#1869](https://github.com/apache/datafusion-sqlparser-rs/pull/1869) (osipovartem)
- MySQL: Support `index_name` in FK constraints [#1871](https://github.com/apache/datafusion-sqlparser-rs/pull/1871) (MohamedAbdeen21)
- Postgres: Apply `ONLY` keyword per table in TRUNCATE stmt [#1872](https://github.com/apache/datafusion-sqlparser-rs/pull/1872) (MohamedAbdeen21)
- Fix `CASE` expression spans [#1874](https://github.com/apache/datafusion-sqlparser-rs/pull/1874) (eliaperantoni)
- MySQL: `[[NOT] ENFORCED]` in CHECK constraint [#1870](https://github.com/apache/datafusion-sqlparser-rs/pull/1870) (MohamedAbdeen21)
- Add support for `CREATE SCHEMA WITH ( <properties> )` [#1877](https://github.com/apache/datafusion-sqlparser-rs/pull/1877) (utay)
- Add support for `ALTER TABLE DROP INDEX` [#1865](https://github.com/apache/datafusion-sqlparser-rs/pull/1865) (vimko)
- chore: Replace archived actions-rs/install action [#1876](https://github.com/apache/datafusion-sqlparser-rs/pull/1876) (assignUser)
- Allow `IF NOT EXISTS` after table name for Snowflake [#1881](https://github.com/apache/datafusion-sqlparser-rs/pull/1881) (bombsimon)
- Support `DISTINCT AS { STRUCT | VALUE }` for BigQuery [#1880](https://github.com/apache/datafusion-sqlparser-rs/pull/1880) (bombsimon)
## Credits
Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) per contributor.
```
7 Ophir LOJKINE
6 Andrew Harper
6 Mohamed Abdeen
3 Luca Cappelletti
2 Denys Tsomenko
2 Simon Sawert
1 Andrew Lamb
1 Artem Osipov
1 Chen Chongchen
1 Dmitriy Mazurin
1 Elia Perantoni
1 Hendrik Makait
1 Jacob Wujciak-Jens
1 Simon Vandel Sillesen
1 Yannick Utard
1 benrsatori
1 dependabot[bot]
1 hulk
1 vimko
```
Thank you also to everyone who contributed in other ways such as filing issues, reviewing PRs, and providing feedback on this release.

41
derive/Cargo.toml Normal file
View file

@ -0,0 +1,41 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
[package]
name = "sqlparser_derive"
description = "Procedural (proc) macros for sqlparser"
version = "0.3.0"
authors = ["sqlparser-rs authors"]
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
documentation = "https://docs.rs/sqlparser_derive/"
keywords = ["ansi", "sql", "lexer", "parser"]
repository = "https://github.com/sqlparser-rs/sqlparser-rs"
license = "Apache-2.0"
include = [
"src/**/*.rs",
"Cargo.toml",
"LICENSE.TXT",
]
edition = "2021"
[lib]
proc-macro = true
[dependencies]
syn = { version = "2.0", default-features = false, features = ["printing", "parsing", "derive", "proc-macro"] }
proc-macro2 = "1.0"
quote = "1.0"

1
derive/LICENSE.TXT Symbolic link
View file

@ -0,0 +1 @@
../LICENSE.TXT

217
derive/README.md Normal file
View file

@ -0,0 +1,217 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# SQL Parser Derive Macro
## Visit
This crate contains a procedural macro that can automatically derive
implementations of the `Visit` trait in the [sqlparser](https://crates.io/crates/sqlparser) crate
```rust
#[derive(Visit, VisitMut)]
struct Foo {
boolean: bool,
bar: Bar,
}
#[derive(Visit, VisitMut)]
enum Bar {
A(),
B(String, bool),
C { named: i32 },
}
```
Will generate code akin to
```rust
impl Visit for Foo {
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
self.boolean.visit(visitor)?;
self.bar.visit(visitor)?;
ControlFlow::Continue(())
}
}
impl Visit for Bar {
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
match self {
Self::A() => {}
Self::B(_1, _2) => {
_1.visit(visitor)?;
_2.visit(visitor)?;
}
Self::C { named } => {
named.visit(visitor)?;
}
}
ControlFlow::Continue(())
}
}
```
Some types may wish to call a corresponding method on the visitor:
```rust
#[derive(Visit, VisitMut)]
#[visit(with = "visit_expr")]
enum Expr {
IsNull(Box<Expr>),
..
}
```
This will result in the following sequence of visitor calls when an `IsNull`
expression is visited
```
visitor.pre_visit_expr(<is null expr>)
visitor.pre_visit_expr(<is null operand>)
visitor.post_visit_expr(<is null operand>)
visitor.post_visit_expr(<is null expr>)
```
For some types it is only appropriate to call a particular visitor method in
some contexts. For example, not every `ObjectName` refers to a relation.
In these cases, the `visit` attribute can be used on the field for which we'd
like to call the method:
```rust
#[derive(Visit, VisitMut)]
#[visit(with = "visit_table_factor")]
pub enum TableFactor {
Table {
#[visit(with = "visit_relation")]
name: ObjectName,
alias: Option<TableAlias>,
},
..
}
```
This will generate
```rust
impl Visit for TableFactor {
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
visitor.pre_visit_table_factor(self)?;
match self {
Self::Table { name, alias } => {
visitor.pre_visit_relation(name)?;
name.visit(visitor)?;
visitor.post_visit_relation(name)?;
alias.visit(visitor)?;
}
}
visitor.post_visit_table_factor(self)?;
ControlFlow::Continue(())
}
}
```
Note that annotating both the type and the field is incorrect as it will result
in redundant calls to the method. For example
```rust
#[derive(Visit, VisitMut)]
#[visit(with = "visit_expr")]
enum Expr {
IsNull(#[visit(with = "visit_expr")] Box<Expr>),
..
}
```
will result in these calls to the visitor
```
visitor.pre_visit_expr(<is null expr>)
visitor.pre_visit_expr(<is null operand>)
visitor.pre_visit_expr(<is null operand>)
visitor.post_visit_expr(<is null operand>)
visitor.post_visit_expr(<is null operand>)
visitor.post_visit_expr(<is null expr>)
```
If the field is a `Option` and add `#[with = "visit_xxx"]` to the field, the generated code
will try to access the field only if it is `Some`:
```rust
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ShowStatementIn {
pub clause: ShowStatementInClause,
pub parent_type: Option<ShowStatementInParentType>,
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub parent_name: Option<ObjectName>,
}
```
This will generate
```rust
impl sqlparser::ast::Visit for ShowStatementIn {
fn visit<V: sqlparser::ast::Visitor>(
&self,
visitor: &mut V,
) -> ::std::ops::ControlFlow<V::Break> {
sqlparser::ast::Visit::visit(&self.clause, visitor)?;
sqlparser::ast::Visit::visit(&self.parent_type, visitor)?;
if let Some(value) = &self.parent_name {
visitor.pre_visit_relation(value)?;
sqlparser::ast::Visit::visit(value, visitor)?;
visitor.post_visit_relation(value)?;
}
::std::ops::ControlFlow::Continue(())
}
}
impl sqlparser::ast::VisitMut for ShowStatementIn {
fn visit<V: sqlparser::ast::VisitorMut>(
&mut self,
visitor: &mut V,
) -> ::std::ops::ControlFlow<V::Break> {
sqlparser::ast::VisitMut::visit(&mut self.clause, visitor)?;
sqlparser::ast::VisitMut::visit(&mut self.parent_type, visitor)?;
if let Some(value) = &mut self.parent_name {
visitor.pre_visit_relation(value)?;
sqlparser::ast::VisitMut::visit(value, visitor)?;
visitor.post_visit_relation(value)?;
}
::std::ops::ControlFlow::Continue(())
}
}
```
## Releasing
This crate's release is not automated. Instead it is released manually as needed
Steps:
1. Update the version in `Cargo.toml`
2. Update the corresponding version in `../Cargo.toml`
3. Commit via PR
4. Publish to crates.io:
```shell
# update to latest checked in main branch and publish via
cargo publish
```

291
derive/src/lib.rs Normal file
View file

@ -0,0 +1,291 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{
parse::{Parse, ParseStream},
parse_macro_input, parse_quote, Attribute, Data, DeriveInput, Fields, GenericParam, Generics,
Ident, Index, LitStr, Meta, Token, Type, TypePath,
};
use syn::{Path, PathArguments};
/// Implementation of `[#derive(Visit)]`
#[proc_macro_derive(VisitMut, attributes(visit))]
pub fn derive_visit_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_visit(
input,
&VisitType {
visit_trait: quote!(VisitMut),
visitor_trait: quote!(VisitorMut),
modifier: Some(quote!(mut)),
},
)
}
/// Implementation of `[#derive(Visit)]`
#[proc_macro_derive(Visit, attributes(visit))]
pub fn derive_visit_immutable(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_visit(
input,
&VisitType {
visit_trait: quote!(Visit),
visitor_trait: quote!(Visitor),
modifier: None,
},
)
}
struct VisitType {
visit_trait: TokenStream,
visitor_trait: TokenStream,
modifier: Option<TokenStream>,
}
fn derive_visit(input: proc_macro::TokenStream, visit_type: &VisitType) -> proc_macro::TokenStream {
// Parse the input tokens into a syntax tree.
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let VisitType {
visit_trait,
visitor_trait,
modifier,
} = visit_type;
let attributes = Attributes::parse(&input.attrs);
// Add a bound `T: Visit` to every type parameter T.
let generics = add_trait_bounds(input.generics, visit_type);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let (pre_visit, post_visit) = attributes.visit(quote!(self));
let children = visit_children(&input.data, visit_type);
let expanded = quote! {
// The generated impl.
// Note that it uses [`recursive::recursive`] to protect from stack overflow.
// See tests in https://github.com/apache/datafusion-sqlparser-rs/pull/1522/ for more info.
impl #impl_generics sqlparser::ast::#visit_trait for #name #ty_generics #where_clause {
#[cfg_attr(feature = "recursive-protection", recursive::recursive)]
fn visit<V: sqlparser::ast::#visitor_trait>(
&#modifier self,
visitor: &mut V
) -> ::std::ops::ControlFlow<V::Break> {
#pre_visit
#children
#post_visit
::std::ops::ControlFlow::Continue(())
}
}
};
proc_macro::TokenStream::from(expanded)
}
/// Parses attributes that can be provided to this macro
///
/// `#[visit(leaf, with = "visit_expr")]`
#[derive(Default)]
struct Attributes {
/// Content for the `with` attribute
with: Option<Ident>,
}
struct WithIdent {
with: Option<Ident>,
}
impl Parse for WithIdent {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
let mut result = WithIdent { with: None };
let ident = input.parse::<Ident>()?;
if ident != "with" {
return Err(syn::Error::new(
ident.span(),
"Expected identifier to be `with`",
));
}
input.parse::<Token!(=)>()?;
let s = input.parse::<LitStr>()?;
result.with = Some(format_ident!("{}", s.value(), span = s.span()));
Ok(result)
}
}
impl Attributes {
fn parse(attrs: &[Attribute]) -> Self {
let mut out = Self::default();
for attr in attrs {
if let Meta::List(ref metalist) = attr.meta {
if metalist.path.is_ident("visit") {
match syn::parse2::<WithIdent>(metalist.tokens.clone()) {
Ok(with_ident) => {
out.with = with_ident.with;
}
Err(e) => {
panic!("{}", e);
}
}
}
}
}
out
}
/// Returns the pre and post visit token streams
fn visit(&self, s: TokenStream) -> (Option<TokenStream>, Option<TokenStream>) {
let pre_visit = self.with.as_ref().map(|m| {
let m = format_ident!("pre_{}", m);
quote!(visitor.#m(#s)?;)
});
let post_visit = self.with.as_ref().map(|m| {
let m = format_ident!("post_{}", m);
quote!(visitor.#m(#s)?;)
});
(pre_visit, post_visit)
}
}
// Add a bound `T: Visit` to every type parameter T.
fn add_trait_bounds(mut generics: Generics, VisitType { visit_trait, .. }: &VisitType) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param
.bounds
.push(parse_quote!(sqlparser::ast::#visit_trait));
}
}
generics
}
// Generate the body of the visit implementation for the given type
fn visit_children(
data: &Data,
VisitType {
visit_trait,
modifier,
..
}: &VisitType,
) -> TokenStream {
match data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let name = &f.ident;
let is_option = is_option(&f.ty);
let attributes = Attributes::parse(&f.attrs);
if is_option && attributes.with.is_some() {
let (pre_visit, post_visit) = attributes.visit(quote!(value));
quote_spanned!(f.span() =>
if let Some(value) = &#modifier self.#name {
#pre_visit sqlparser::ast::#visit_trait::visit(value, visitor)?; #post_visit
}
)
} else {
let (pre_visit, post_visit) = attributes.visit(quote!(&#modifier self.#name));
quote_spanned!(f.span() =>
#pre_visit sqlparser::ast::#visit_trait::visit(&#modifier self.#name, visitor)?; #post_visit
)
}
});
quote! {
#(#recurse)*
}
}
Fields::Unnamed(fields) => {
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
let index = Index::from(i);
let attributes = Attributes::parse(&f.attrs);
let (pre_visit, post_visit) = attributes.visit(quote!(&self.#index));
quote_spanned!(f.span() => #pre_visit sqlparser::ast::#visit_trait::visit(&#modifier self.#index, visitor)?; #post_visit)
});
quote! {
#(#recurse)*
}
}
Fields::Unit => {
quote!()
}
},
Data::Enum(data) => {
let statements = data.variants.iter().map(|v| {
let name = &v.ident;
match &v.fields {
Fields::Named(fields) => {
let names = fields.named.iter().map(|f| &f.ident);
let visit = fields.named.iter().map(|f| {
let name = &f.ident;
let attributes = Attributes::parse(&f.attrs);
let (pre_visit, post_visit) = attributes.visit(name.to_token_stream());
quote_spanned!(f.span() => #pre_visit sqlparser::ast::#visit_trait::visit(#name, visitor)?; #post_visit)
});
quote!(
Self::#name { #(#names),* } => {
#(#visit)*
}
)
}
Fields::Unnamed(fields) => {
let names = fields.unnamed.iter().enumerate().map(|(i, f)| format_ident!("_{}", i, span = f.span()));
let visit = fields.unnamed.iter().enumerate().map(|(i, f)| {
let name = format_ident!("_{}", i);
let attributes = Attributes::parse(&f.attrs);
let (pre_visit, post_visit) = attributes.visit(name.to_token_stream());
quote_spanned!(f.span() => #pre_visit sqlparser::ast::#visit_trait::visit(#name, visitor)?; #post_visit)
});
quote! {
Self::#name ( #(#names),*) => {
#(#visit)*
}
}
}
Fields::Unit => {
quote! {
Self::#name => {}
}
}
}
});
quote! {
match self {
#(#statements),*
}
}
}
Data::Union(_) => unimplemented!(),
}
}
fn is_option(ty: &Type) -> bool {
if let Type::Path(TypePath {
path: Path { segments, .. },
..
}) = ty
{
if let Some(segment) = segments.last() {
if segment.ident == "Option" {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
return args.args.len() == 1;
}
}
}
}
false
}

187
dev/release/README.md Normal file
View file

@ -0,0 +1,187 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
## Process Overview
As part of the Apache governance model, official releases consist of signed
source tarballs approved by the DataFusion PMC.
We then use the code in the approved artifacts to release to crates.io.
### Change Log
We maintain a `CHANGELOG.md` so our users know what has been changed between releases.
You will need a GitHub Personal Access Token for the following steps. Follow
[these instructions](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
to generate one if you do not already have one.
The changelog is generated using a Python script which needs `PyGitHub`, installed using pip:
```shell
pip3 install PyGitHub
```
To generate the changelog, set the `GITHUB_TOKEN` environment variable to a valid token and then run the script
providing two commit ids or tags followed by the version number of the release being created. The following
example generates a change log of all changes between the first commit and the current HEAD revision.
```shell
export GITHUB_TOKEN=<your-token-here>
python ./dev/release/generate-changelog.py v0.51.0 HEAD 0.52.0 > changelog/0.52.0.md
```
This script creates a changelog from GitHub PRs based on the labels associated with them as well as looking for
titles starting with `feat:`, `fix:`, or `docs:`.
Add an entry to CHANGELOG.md for the new version
## Prepare release commits and PR
### Update Version
Checkout the main commit to be released
```shell
git fetch apache
git checkout apache/main
```
Manually update the version in the root `Cargo.toml` to the release version (e.g. `0.52.0`).
Lastly commit the version change:
```shell
git commit -a -m 'Update version'
```
## Prepare release candidate artifacts
After the PR gets merged, you are ready to create release artifacts from the
merged commit.
(Note you need to be a committer to run these scripts as they upload to the apache svn distribution servers)
### Pick a Release Candidate (RC) number
Pick numbers in sequential order, with `0` for `rc0`, `1` for `rc1`, etc.
### Create git tag for the release:
While the official release artifacts are signed tarballs and zip files, we also
tag the commit it was created for convenience and code archaeology.
Using a string such as `v0.52.0` as the `<version>`, create and push the tag by running these commands:
For example to tag version `0.52.0`
```shell
git fetch apache
git tag v0.52.0-rc1 apache/main
# push tag to Github remote
git push apache v0.52.0-rc1
```
### Create, sign, and upload artifacts
Run `create-tarball.sh` with the `<version>` tag and `<rc>` and you found in previous steps:
```shell
GITHUB_TOKEN=<TOKEN> ./dev/release/create-tarball.sh 0.52.0 1
```
The `create-tarball.sh` script
1. creates and uploads all release candidate artifacts to the [datafusion
dev](https://dist.apache.org/repos/dist/dev/datafusion) location on the
apache distribution svn server
2. provide you an email template to
send to dev@datafusion.apache.org for release voting.
### Vote on Release Candidate artifacts
Send the email output from the script to dev@datafusion.apache.org.
For the release to become "official" it needs at least three PMC members to vote +1 on it.
### Verifying Release Candidates
The `dev/release/verify-release-candidate.sh` is a script in this repository that can assist in the verification process. Run it like:
```shell
./dev/release/verify-release-candidate.sh 0.52.0 1
```
#### If the release is not approved
If the release is not approved, fix whatever the problem is, merge changelog
changes into main if there is any and try again with the next RC number.
## Finalize the release
NOTE: steps in this section can only be done by PMC members.
### After the release is approved
Move artifacts to the release location in SVN, using the `release-tarball.sh` script:
```shell
./dev/release/release-tarball.sh 0.52.0 1
```
Promote the rc tag to the release tag
```shell
git tag v0.52.0 v0.52.0-rc3
git push apache v0.52.0
```
Congratulations! The release is now official!
### Publish on Crates.io
Only approved releases of the tarball should be published to
crates.io, in order to conform to Apache Software Foundation
governance standards.
A DataFusion committer can publish this crate after an official project release has
been made to crates.io using the following instructions.
Follow [these
instructions](https://doc.rust-lang.org/cargo/reference/publishing.html) to
create an account and login to crates.io before asking to be added as an owner
to the sqlparser DataFusion crates.
Download and unpack the official release tarball
Verify that the Cargo.toml in the tarball contains the correct version
(e.g. `version = "0.52.0"`) and then publish the crates by running the following commands
```shell
cargo publish
```
If necessary, also publish the `sqlparser_derive` crate:
crates.io homepage: https://crates.io/crates/sqlparser_derive
```shell
(cd derive && cargo publish
```

View file

@ -0,0 +1,59 @@
#!/usr/bin/python
##############################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
##############################################################################
import fnmatch
import re
import sys
import xml.etree.ElementTree as ET
if len(sys.argv) != 3:
sys.stderr.write("Usage: %s exclude_globs.lst rat_report.xml\n" %
sys.argv[0])
sys.exit(1)
exclude_globs_filename = sys.argv[1]
xml_filename = sys.argv[2]
globs = [line.strip() for line in open(exclude_globs_filename, "r")]
tree = ET.parse(xml_filename)
root = tree.getroot()
resources = root.findall('resource')
all_ok = True
for r in resources:
approvals = r.findall('license-approval')
if not approvals or approvals[0].attrib['name'] == 'true':
continue
clean_name = re.sub('^[^/]+/', '', r.attrib['name'])
excluded = False
for g in globs:
if fnmatch.fnmatch(clean_name, g):
excluded = True
break
if not excluded:
sys.stdout.write("NOT APPROVED: %s (%s): %s\n" % (
clean_name, r.attrib['name'], approvals[0].attrib['name']))
all_ok = False
if not all_ok:
sys.exit(1)
print('OK')
sys.exit(0)

135
dev/release/create-tarball.sh Executable file
View file

@ -0,0 +1,135 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Adapted from https://github.com/apache/datafusion/tree/master/dev/release/create-tarball.sh
# This script creates a signed tarball in
# dev/dist/apache-datafusion-sqlparser-rs-<version>-rc.tar.gz and uploads it to
# the "dev" area of the dist.apache.datafusion repository and prepares an
# email for sending to the dev@datafusion.apache.org list for a formal
# vote.
#
# See release/README.md for full release instructions
#
# Requirements:
#
# 1. gpg setup for signing and have uploaded your public
# signature to https://pgp.mit.edu/
#
# 2. Logged into the apache svn server with the appropriate
# credentials
#
# 3. Install the requests python package
#
#
# Based in part on 02-source.sh from apache/arrow
#
set -e
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCE_TOP_DIR="$(cd "${SOURCE_DIR}/../../" && pwd)"
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <version> <rc>"
echo "ex. $0 0.52.0 2"
exit
fi
if [[ -z "${GITHUB_TOKEN}" ]]; then
echo "Please set personal github token through GITHUB_TOKEN environment variable"
exit
fi
version=$1
rc=$2
tag="v${version}-rc${rc}"
echo "Attempting to create ${tarball} from tag ${tag}"
release_hash=$(cd "${SOURCE_TOP_DIR}" && git rev-list --max-count=1 ${tag})
release=apache-datafusion-sqlparser-rs-${version}
distdir=${SOURCE_TOP_DIR}/dev/dist/${release}-rc${rc}
tarname=${release}.tar.gz
tarball=${distdir}/${tarname}
url="https://dist.apache.org/repos/dist/dev/datafusion/${release}-rc${rc}"
if [ -z "$release_hash" ]; then
echo "Cannot continue: unknown git tag: ${tag}"
fi
echo "Draft email for dev@datafusion.apache.org mailing list"
echo ""
echo "---------------------------------------------------------"
cat <<MAIL
To: dev@datafusion.apache.org
Subject: [VOTE] Release Apache DataFusion sqlparser-rs ${version} RC${rc}
Hi,
I would like to propose a release of Apache DataFusion sqlparser-rs version ${version}.
This release candidate is based on commit: ${release_hash} [1]
The proposed release tarball and signatures are hosted at [2].
The changelog is located at [3].
Please download, verify checksums and signatures, run the unit tests, and vote
on the release. The vote will be open for at least 72 hours.
Only votes from PMC members are binding, but all members of the community are
encouraged to test the release and vote with "(non-binding)".
The standard verification procedure is documented at https://github.com/apache/datafusion-sqlparser-rs/blob/main/dev/release/README.md#verifying-release-candidates.
[ ] +1 Release this as Apache DataFusion sqlparser-rs ${version}
[ ] +0
[ ] -1 Do not release this as Apache DataFusion sqlparser-rs ${version} because...
Here is my vote:
+1
[1]: https://github.com/apache/datafusion-sqlparser-rs/tree/${release_hash}
[2]: ${url}
[3]: https://github.com/apache/datafusion-sqlparser-rs/blob/${release_hash}/CHANGELOG.md
MAIL
echo "---------------------------------------------------------"
# create <tarball> containing the files in git at $release_hash
# the files in the tarball are prefixed with {version} (e.g. 4.0.1)
mkdir -p ${distdir}
(cd "${SOURCE_TOP_DIR}" && git archive ${release_hash} --prefix ${release}/ | gzip > ${tarball})
echo "Running rat license checker on ${tarball}"
${SOURCE_DIR}/run-rat.sh ${tarball}
echo "Signing tarball and creating checksums"
gpg --armor --output ${tarball}.asc --detach-sig ${tarball}
# create signing with relative path of tarball
# so that they can be verified with a command such as
# shasum --check apache-datafusion-sqlparser-rs-0.52.0-rc1.tar.gz.sha512
(cd ${distdir} && shasum -a 256 ${tarname}) > ${tarball}.sha256
(cd ${distdir} && shasum -a 512 ${tarname}) > ${tarball}.sha512
echo "Uploading to sqlparser-rs dist/dev to ${url}"
svn co --depth=empty https://dist.apache.org/repos/dist/dev/datafusion ${SOURCE_TOP_DIR}/dev/dist
svn add ${distdir}
svn ci -m "Apache DataFusion ${version} ${rc}" ${distdir}

165
dev/release/generate-changelog.py Executable file
View file

@ -0,0 +1,165 @@
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
from github import Github
import os
import re
import subprocess
def print_pulls(repo_name, title, pulls):
if len(pulls) > 0:
print("**{}:**".format(title))
print()
for (pull, commit) in pulls:
url = "https://github.com/{}/pull/{}".format(repo_name, pull.number)
author = f"({commit.author.login})" if commit.author else ''
print("- {} [#{}]({}) {}".format(pull.title, pull.number, url, author))
print()
def generate_changelog(repo, repo_name, tag1, tag2, version):
# get a list of commits between two tags
print(f"Fetching list of commits between {tag1} and {tag2}", file=sys.stderr)
comparison = repo.compare(tag1, tag2)
# get the pull requests for these commits
print("Fetching pull requests", file=sys.stderr)
unique_pulls = []
all_pulls = []
for commit in comparison.commits:
pulls = commit.get_pulls()
for pull in pulls:
# there can be multiple commits per PR if squash merge is not being used and
# in this case we should get all the author names, but for now just pick one
if pull.number not in unique_pulls:
unique_pulls.append(pull.number)
all_pulls.append((pull, commit))
# we split the pulls into categories
breaking = []
bugs = []
docs = []
enhancements = []
performance = []
other = []
# categorize the pull requests based on GitHub labels
print("Categorizing pull requests", file=sys.stderr)
for (pull, commit) in all_pulls:
# see if PR title uses Conventional Commits
cc_type = ''
cc_scope = ''
cc_breaking = ''
parts = re.findall(r'^([a-z]+)(\([a-z]+\))?(!)?:', pull.title)
if len(parts) == 1:
parts_tuple = parts[0]
cc_type = parts_tuple[0] # fix, feat, docs, chore
cc_scope = parts_tuple[1] # component within project
cc_breaking = parts_tuple[2] == '!'
labels = [label.name for label in pull.labels]
if 'api change' in labels or cc_breaking:
breaking.append((pull, commit))
elif 'bug' in labels or cc_type == 'fix':
bugs.append((pull, commit))
elif 'performance' in labels or cc_type == 'perf':
performance.append((pull, commit))
elif 'enhancement' in labels or cc_type == 'feat':
enhancements.append((pull, commit))
elif 'documentation' in labels or cc_type == 'docs' or cc_type == 'doc':
docs.append((pull, commit))
else:
other.append((pull, commit))
# produce the changelog content
print("Generating changelog content", file=sys.stderr)
# ASF header
print("""<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->\n""")
print(f"# sqlparser-rs {version} Changelog\n")
# get the number of commits
commit_count = subprocess.check_output(f"git log --pretty=oneline {tag1}..{tag2} | wc -l", shell=True, text=True).strip()
# get number of contributors
contributor_count = subprocess.check_output(f"git shortlog -sn {tag1}..{tag2} | wc -l", shell=True, text=True).strip()
print(f"This release consists of {commit_count} commits from {contributor_count} contributors. "
f"See credits at the end of this changelog for more information.\n")
print_pulls(repo_name, "Breaking changes", breaking)
print_pulls(repo_name, "Performance related", performance)
print_pulls(repo_name, "Implemented enhancements", enhancements)
print_pulls(repo_name, "Fixed bugs", bugs)
print_pulls(repo_name, "Documentation updates", docs)
print_pulls(repo_name, "Other", other)
# show code contributions
credits = subprocess.check_output(f"git shortlog -sn {tag1}..{tag2}", shell=True, text=True).rstrip()
print("## Credits\n")
print("Thank you to everyone who contributed to this release. Here is a breakdown of commits (PRs merged) "
"per contributor.\n")
print("```")
print(credits)
print("```\n")
print("Thank you also to everyone who contributed in other ways such as filing issues, reviewing "
"PRs, and providing feedback on this release.\n")
def cli(args=None):
"""Process command line arguments."""
if not args:
args = sys.argv[1:]
parser = argparse.ArgumentParser()
parser.add_argument("tag1", help="The previous commit or tag (e.g. 0.1.0)")
parser.add_argument("tag2", help="The current commit or tag (e.g. HEAD)")
parser.add_argument("version", help="The version number to include in the changelog")
args = parser.parse_args()
token = os.getenv("GITHUB_TOKEN")
project = "apache/datafusion-sqlparser-rs"
g = Github(token)
repo = g.get_repo(project)
generate_changelog(repo, project, args.tag1, args.tag2, args.version)
if __name__ == "__main__":
cli()

View file

@ -0,0 +1,8 @@
.tool-versions
target/*
**.gitignore
rat.txt
dev/release/rat_exclude_files.txt
sqlparser_bench/img/flamegraph.svg
**Cargo.lock
filtered_rat.txt

74
dev/release/release-tarball.sh Executable file
View file

@ -0,0 +1,74 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Adapted from https://github.com/apache/arrow-rs/tree/master/dev/release/release-tarball.sh
# This script copies a tarball from the "dev" area of the
# dist.apache.datafusion repository to the "release" area
#
# This script should only be run after the release has been approved
# by the Apache DataFusion PMC committee.
#
# See release/README.md for full release instructions
#
# Based in part on post-01-upload.sh from apache/arrow
set -e
set -u
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <version> <rc-num>"
echo "ex. $0 0.52.0 2"
exit
fi
version=$1
rc=$2
tmp_dir=tmp-apache-datafusion-dist
echo "Recreate temporary directory: ${tmp_dir}"
rm -rf ${tmp_dir}
mkdir -p ${tmp_dir}
echo "Clone dev dist repository"
svn \
co \
https://dist.apache.org/repos/dist/dev/datafusion/apache-datafusion-sqlparser-rs-${version}-rc${rc} \
${tmp_dir}/dev
echo "Clone release dist repository"
svn co https://dist.apache.org/repos/dist/release/datafusion ${tmp_dir}/release
echo "Copy ${version}-rc${rc} to release working copy"
release_version=datafusion-sqlparser-rs-${version}
mkdir -p ${tmp_dir}/release/${release_version}
cp -r ${tmp_dir}/dev/* ${tmp_dir}/release/${release_version}/
svn add ${tmp_dir}/release/${release_version}
echo "Commit release"
svn ci -m "Apache DataFusion sqlparser-rs ${version}" ${tmp_dir}/release
echo "Clean up"
rm -rf ${tmp_dir}
echo "Success! The release is available here:"
echo " https://dist.apache.org/repos/dist/release/datafusion/${release_version}"

43
dev/release/run-rat.sh Executable file
View file

@ -0,0 +1,43 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
RAT_VERSION=0.13
# download apache rat
if [ ! -f apache-rat-${RAT_VERSION}.jar ]; then
curl -s https://repo1.maven.org/maven2/org/apache/rat/apache-rat/${RAT_VERSION}/apache-rat-${RAT_VERSION}.jar > apache-rat-${RAT_VERSION}.jar
fi
RAT="java -jar apache-rat-${RAT_VERSION}.jar -x "
RELEASE_DIR=$(cd "$(dirname "$BASH_SOURCE")"; pwd)
# generate the rat report
$RAT $1 > rat.txt
python $RELEASE_DIR/check-rat-report.py $RELEASE_DIR/rat_exclude_files.txt rat.txt > filtered_rat.txt
cat filtered_rat.txt
UNAPPROVED=`cat filtered_rat.txt | grep "NOT APPROVED" | wc -l`
if [ "0" -eq "${UNAPPROVED}" ]; then
echo "No unapproved licenses"
else
echo "${UNAPPROVED} unapproved licences. Check rat report: rat.txt"
exit 1
fi

View file

@ -0,0 +1,152 @@
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
case $# in
2) VERSION="$1"
RC_NUMBER="$2"
;;
*) echo "Usage: $0 X.Y.Z RC_NUMBER"
exit 1
;;
esac
set -e
set -x
set -o pipefail
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
ARROW_DIR="$(dirname $(dirname ${SOURCE_DIR}))"
ARROW_DIST_URL='https://dist.apache.org/repos/dist/dev/datafusion'
download_dist_file() {
curl \
--silent \
--show-error \
--fail \
--location \
--remote-name $ARROW_DIST_URL/$1
}
download_rc_file() {
download_dist_file apache-datafusion-sqlparser-rs-${VERSION}-rc${RC_NUMBER}/$1
}
import_gpg_keys() {
download_dist_file KEYS
gpg --import KEYS
}
if type shasum >/dev/null 2>&1; then
sha256_verify="shasum -a 256 -c"
sha512_verify="shasum -a 512 -c"
else
sha256_verify="sha256sum -c"
sha512_verify="sha512sum -c"
fi
fetch_archive() {
local dist_name=$1
download_rc_file ${dist_name}.tar.gz
download_rc_file ${dist_name}.tar.gz.asc
download_rc_file ${dist_name}.tar.gz.sha256
download_rc_file ${dist_name}.tar.gz.sha512
verify_dir_artifact_signatures
}
verify_dir_artifact_signatures() {
# verify the signature and the checksums of each artifact
find . -name '*.asc' | while read sigfile; do
artifact=${sigfile/.asc/}
gpg --verify $sigfile $artifact || exit 1
# go into the directory because the checksum files contain only the
# basename of the artifact
pushd $(dirname $artifact)
base_artifact=$(basename $artifact)
${sha256_verify} $base_artifact.sha256 || exit 1
${sha512_verify} $base_artifact.sha512 || exit 1
popd
done
}
setup_tempdir() {
cleanup() {
if [ "${TEST_SUCCESS}" = "yes" ]; then
rm -fr "${ARROW_TMPDIR}"
else
echo "Failed to verify release candidate. See ${ARROW_TMPDIR} for details."
fi
}
if [ -z "${ARROW_TMPDIR}" ]; then
# clean up automatically if ARROW_TMPDIR is not defined
ARROW_TMPDIR=$(mktemp -d -t "$1.XXXXX")
trap cleanup EXIT
else
# don't clean up automatically
mkdir -p "${ARROW_TMPDIR}"
fi
}
test_source_distribution() {
# install rust toolchain in a similar fashion like test-miniconda
export RUSTUP_HOME=$PWD/test-rustup
export CARGO_HOME=$PWD/test-rustup
curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path
export PATH=$RUSTUP_HOME/bin:$PATH
source $RUSTUP_HOME/env
# build and test rust
# raises on any formatting errors
rustup component add rustfmt --toolchain stable
cargo fmt --all -- --check
cargo build
cargo test --all-features
if ( find -iname 'Cargo.toml' | xargs grep SNAPSHOT ); then
echo "Cargo.toml version should not contain SNAPSHOT for releases"
exit 1
fi
# Check that publish works
cargo publish --dry-run
}
TEST_SUCCESS=no
setup_tempdir "datafusion-sqlparser-rs-${VERSION}"
echo "Working in sandbox ${ARROW_TMPDIR}"
cd ${ARROW_TMPDIR}
dist_name="apache-datafusion-sqlparser-rs-${VERSION}"
import_gpg_keys
fetch_archive ${dist_name}
tar xf ${dist_name}.tar.gz
pushd ${dist_name}
test_source_distribution
popd
TEST_SUCCESS=yes
echo 'Release candidate looks good!'
exit 0

25
docs/benchmarking.md Normal file
View file

@ -0,0 +1,25 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Benchmarking
Run `cargo bench` in the project `sqlparser_bench` execute the queries.
It will report results using the `criterion` library to perform the benchmarking.
The bench project lives in another crate, to avoid the negative impact on building the `sqlparser` crate.

View file

@ -1,8 +1,29 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Writing a Custom SQL Parser
I have explored many different ways of building this library to make it easy to extend it for custom SQL dialects. Most of my attempts ended in failure but I have now found a workable solution. It is not without downsides but this seems to be the most pragmatic solution.
The concept is simply to write a new parser that delegates to the ANSI parser so that as much as possible of the core functionality can be re-used.
For an example of this, see the [DataFusion](https://github.com/datafusion-rs/datafusion) project.
I also plan on building in specific support for custom data types, where a lambda function can be passed to the parser to parse data types.
For an example of this, see the [DataFusion](https://github.com/apache/arrow-datafusion) project and its [query planner](https://github.com/apache/arrow-datafusion/tree/master/datafusion/sql).

57
docs/fuzzing.md Normal file
View file

@ -0,0 +1,57 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# Fuzzing
## Installing `honggfuzz`
```
cargo install honggfuzz
```
Install [dependencies](https://github.com/rust-fuzz/honggfuzz-rs#dependencies) for your system.
## Running the fuzzer
Running the fuzzer is as easy as running in the `fuzz` directory.
Choose a target:
These are `[[bin]]` entries in `Cargo.toml`.
List them with `cargo read-manifest | jq '.targets[].name'` from the `fuzz` directory.
Run the fuzzer:
```shell
cd fuzz
cargo hfuzz run <target>
```
After a panic is found, get a stack trace with:
```shell
cargo hfuzz run-debug <target> hfuzz_workspace/<target>/*.fuzz
```
For example, with the `fuzz_parse_sql` target:
```shell
cargo hfuzz run fuzz_parse_sql
cargo hfuzz run-debug fuzz_parse_sql hfuzz_workspace/fuzz_parse_sql/*.fuzz
```

113
examples/cli.rs Normal file
View file

@ -0,0 +1,113 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#![warn(clippy::all)]
//! A small command-line app to run the parser.
//! Run with `cargo run --example cli`
use std::fs;
use std::io::{stdin, Read};
use simple_logger::SimpleLogger;
use sqlparser::dialect::*;
use sqlparser::parser::Parser;
fn main() {
SimpleLogger::new().init().unwrap();
let filename = std::env::args().nth(1).expect(
r#"
No arguments provided!
Usage:
$ cargo run --example cli FILENAME.sql [--dialectname]
To print the parse results as JSON:
$ cargo run --feature json_example --example cli FILENAME.sql [--dialectname]
To read from stdin instead of a file:
$ cargo run --example cli - [--dialectname]
"#,
);
let dialect: Box<dyn Dialect> = match std::env::args().nth(2).unwrap_or_default().as_ref() {
"--ansi" => Box::new(AnsiDialect {}),
"--bigquery" => Box::new(BigQueryDialect {}),
"--postgres" => Box::new(PostgreSqlDialect {}),
"--ms" => Box::new(MsSqlDialect {}),
"--mysql" => Box::new(MySqlDialect {}),
"--snowflake" => Box::new(SnowflakeDialect {}),
"--hive" => Box::new(HiveDialect {}),
"--redshift" => Box::new(RedshiftSqlDialect {}),
"--clickhouse" => Box::new(ClickHouseDialect {}),
"--duckdb" => Box::new(DuckDbDialect {}),
"--sqlite" => Box::new(SQLiteDialect {}),
"--generic" | "" => Box::new(GenericDialect {}),
s => panic!("Unexpected parameter: {s}"),
};
let contents = if filename == "-" {
println!("Parsing from stdin using {dialect:?}");
let mut buf = Vec::new();
stdin()
.read_to_end(&mut buf)
.expect("failed to read from stdin");
String::from_utf8(buf).expect("stdin content wasn't valid utf8")
} else {
println!("Parsing from file '{}' using {:?}", &filename, dialect);
fs::read_to_string(&filename)
.unwrap_or_else(|_| panic!("Unable to read the file {}", &filename))
};
let without_bom = if contents.chars().next().unwrap() as u64 != 0xfeff {
contents.as_str()
} else {
let mut chars = contents.chars();
chars.next();
chars.as_str()
};
let parse_result = Parser::parse_sql(&*dialect, without_bom);
match parse_result {
Ok(statements) => {
println!(
"Round-trip:\n'{}'",
statements
.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>()
.join("\n")
);
if cfg!(feature = "json_example") {
#[cfg(feature = "json_example")]
{
let serialized = serde_json::to_string_pretty(&statements).unwrap();
println!("Serialized as JSON:\n{serialized}");
}
} else {
println!("Parse results:\n{statements:#?}");
}
std::process::exit(0);
}
Err(e) => {
println!("Error during parsing: {e:?}");
std::process::exit(1);
}
}
}

View file

@ -1,6 +1,24 @@
extern crate sqlparser;
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use sqlparser::sqlparser::*;
#![warn(clippy::all)]
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::*;
fn main() {
let sql = "SELECT a, b, 123, myfunc(b) \
@ -8,7 +26,9 @@ fn main() {
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";
let ast = Parser::parse_sql(sql.to_string()).unwrap();
let dialect = GenericDialect {};
println!("AST: {:?}", ast);
let ast = Parser::parse_sql(&dialect, sql).unwrap();
println!("AST: {ast:?}");
}

3
fuzz/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
corpus
hfuzz_target
hfuzz_workspace

34
fuzz/Cargo.toml Normal file
View file

@ -0,0 +1,34 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
[package]
name = "fuzz"
version = "0.1.0"
edition = "2018"
publish = false
[dependencies]
honggfuzz = "0.5.54"
sqlparser = { path = ".." }
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[[bin]]
name = "fuzz_parse_sql"
path = "fuzz_targets/fuzz_parse_sql.rs"

View file

@ -0,0 +1,29 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use honggfuzz::fuzz;
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
fn main() {
loop {
fuzz!(|data: String| {
let dialect = GenericDialect {};
let _ = Parser::parse_sql(&dialect, &data);
});
}
}

18
rustfmt.toml Normal file
View file

@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# We use rustfmt's default settings to format the source code

View file

@ -0,0 +1,33 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
[package]
name = "sqlparser_bench"
description = "Benchmarks for sqlparser"
version = "0.1.0"
authors = ["Dandandan <danielheres@gmail.com>"]
edition = "2018"
[dependencies]
sqlparser = { path = "../" }
[dev-dependencies]
criterion = "0.6"
[[bench]]
name = "sqlparser_bench"
harness = false

42
sqlparser_bench/README.md Normal file
View file

@ -0,0 +1,42 @@
<!---
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
Benchmarks for sqlparser. See [the main README](../README.md) for more information.
Note: this is in a separate, non workspace crate to avoid adding a dependency
on `criterion` to the main crate (which complicates testing without std).
# Running Benchmarks
```shell
cargo bench --bench sqlparser_bench
```
# Profiling
Note you can generate a [flamegraph] using the following command:
```shell
cargo flamegraph --bench sqlparser_bench
```
[flamegraph]: https://crates.io/crates/flamegraph
Here is an example flamegraph:
![flamegraph](img/flamegraph.svg)

View file

@ -0,0 +1,86 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use criterion::{criterion_group, criterion_main, Criterion};
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
fn basic_queries(c: &mut Criterion) {
let mut group = c.benchmark_group("sqlparser-rs parsing benchmark");
let dialect = GenericDialect {};
let string = "SELECT * FROM my_table WHERE 1 = 1";
group.bench_function("sqlparser::select", |b| {
b.iter(|| Parser::parse_sql(&dialect, string).unwrap());
});
let with_query = "
WITH derived AS (
SELECT MAX(a) AS max_a,
COUNT(b) AS b_num,
user_id
FROM MY_TABLE
GROUP BY user_id
)
SELECT * FROM my_table
LEFT JOIN derived USING (user_id)
";
group.bench_function("sqlparser::with_select", |b| {
b.iter(|| Parser::parse_sql(&dialect, with_query).unwrap());
});
let large_statement = {
let expressions = (0..1000)
.map(|n| format!("FN_{n}(COL_{n})"))
.collect::<Vec<_>>()
.join(", ");
let tables = (0..1000)
.map(|n| format!("TABLE_{n}"))
.collect::<Vec<_>>()
.join(" JOIN ");
let where_condition = (0..1000)
.map(|n| format!("COL_{n} = {n}"))
.collect::<Vec<_>>()
.join(" OR ");
let order_condition = (0..1000)
.map(|n| format!("COL_{n} DESC"))
.collect::<Vec<_>>()
.join(", ");
format!(
"SELECT {expressions} FROM {tables} WHERE {where_condition} ORDER BY {order_condition}"
)
};
group.bench_function("parse_large_statement", |b| {
b.iter(|| Parser::parse_sql(&dialect, std::hint::black_box(large_statement.as_str())));
});
let large_statement = Parser::parse_sql(&dialect, large_statement.as_str())
.unwrap()
.pop()
.unwrap();
group.bench_function("format_large_statement", |b| {
b.iter(|| {
let _formatted_query = large_statement.to_string();
});
});
}
criterion_group!(benches, basic_queries);
criterion_main!(benches);

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

1057
src/ast/data_type.rs Normal file

File diff suppressed because it is too large Load diff

254
src/ast/dcl.rs Normal file
View file

@ -0,0 +1,254 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement)
//! (commonly referred to as Data Control Language, or DCL)
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use super::{display_comma_separated, Expr, Ident, Password};
use crate::ast::{display_separated, ObjectName};
/// An option in `ROLE` statement.
///
/// <https://www.postgresql.org/docs/current/sql-createrole.html>
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum RoleOption {
BypassRLS(bool),
ConnectionLimit(Expr),
CreateDB(bool),
CreateRole(bool),
Inherit(bool),
Login(bool),
Password(Password),
Replication(bool),
SuperUser(bool),
ValidUntil(Expr),
}
impl fmt::Display for RoleOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RoleOption::BypassRLS(value) => {
write!(f, "{}", if *value { "BYPASSRLS" } else { "NOBYPASSRLS" })
}
RoleOption::ConnectionLimit(expr) => {
write!(f, "CONNECTION LIMIT {expr}")
}
RoleOption::CreateDB(value) => {
write!(f, "{}", if *value { "CREATEDB" } else { "NOCREATEDB" })
}
RoleOption::CreateRole(value) => {
write!(f, "{}", if *value { "CREATEROLE" } else { "NOCREATEROLE" })
}
RoleOption::Inherit(value) => {
write!(f, "{}", if *value { "INHERIT" } else { "NOINHERIT" })
}
RoleOption::Login(value) => {
write!(f, "{}", if *value { "LOGIN" } else { "NOLOGIN" })
}
RoleOption::Password(password) => match password {
Password::Password(expr) => write!(f, "PASSWORD {expr}"),
Password::NullPassword => write!(f, "PASSWORD NULL"),
},
RoleOption::Replication(value) => {
write!(
f,
"{}",
if *value {
"REPLICATION"
} else {
"NOREPLICATION"
}
)
}
RoleOption::SuperUser(value) => {
write!(f, "{}", if *value { "SUPERUSER" } else { "NOSUPERUSER" })
}
RoleOption::ValidUntil(expr) => {
write!(f, "VALID UNTIL {expr}")
}
}
}
}
/// SET config value option:
/// * SET `configuration_parameter` { TO | = } { `value` | DEFAULT }
/// * SET `configuration_parameter` FROM CURRENT
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SetConfigValue {
Default,
FromCurrent,
Value(Expr),
}
/// RESET config option:
/// * RESET `configuration_parameter`
/// * RESET ALL
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ResetConfig {
ALL,
ConfigName(ObjectName),
}
/// An `ALTER ROLE` (`Statement::AlterRole`) operation
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterRoleOperation {
/// Generic
RenameRole {
role_name: Ident,
},
/// MS SQL Server
/// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
AddMember {
member_name: Ident,
},
DropMember {
member_name: Ident,
},
/// PostgreSQL
/// <https://www.postgresql.org/docs/current/sql-alterrole.html>
WithOptions {
options: Vec<RoleOption>,
},
Set {
config_name: ObjectName,
config_value: SetConfigValue,
in_database: Option<ObjectName>,
},
Reset {
config_name: ResetConfig,
in_database: Option<ObjectName>,
},
}
impl fmt::Display for AlterRoleOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlterRoleOperation::RenameRole { role_name } => {
write!(f, "RENAME TO {role_name}")
}
AlterRoleOperation::AddMember { member_name } => {
write!(f, "ADD MEMBER {member_name}")
}
AlterRoleOperation::DropMember { member_name } => {
write!(f, "DROP MEMBER {member_name}")
}
AlterRoleOperation::WithOptions { options } => {
write!(f, "WITH {}", display_separated(options, " "))
}
AlterRoleOperation::Set {
config_name,
config_value,
in_database,
} => {
if let Some(database_name) = in_database {
write!(f, "IN DATABASE {database_name} ")?;
}
match config_value {
SetConfigValue::Default => write!(f, "SET {config_name} TO DEFAULT"),
SetConfigValue::FromCurrent => write!(f, "SET {config_name} FROM CURRENT"),
SetConfigValue::Value(expr) => write!(f, "SET {config_name} TO {expr}"),
}
}
AlterRoleOperation::Reset {
config_name,
in_database,
} => {
if let Some(database_name) = in_database {
write!(f, "IN DATABASE {database_name} ")?;
}
match config_name {
ResetConfig::ALL => write!(f, "RESET ALL"),
ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
}
}
}
}
}
/// A `USE` (`Statement::Use`) operation
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum Use {
Catalog(ObjectName), // e.g. `USE CATALOG foo.bar`
Schema(ObjectName), // e.g. `USE SCHEMA foo.bar`
Database(ObjectName), // e.g. `USE DATABASE foo.bar`
Warehouse(ObjectName), // e.g. `USE WAREHOUSE foo.bar`
Role(ObjectName), // e.g. `USE ROLE PUBLIC`
SecondaryRoles(SecondaryRoles), // e.g. `USE SECONDARY ROLES ALL`
Object(ObjectName), // e.g. `USE foo.bar`
Default, // e.g. `USE DEFAULT`
}
impl fmt::Display for Use {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("USE ")?;
match self {
Use::Catalog(name) => write!(f, "CATALOG {name}"),
Use::Schema(name) => write!(f, "SCHEMA {name}"),
Use::Database(name) => write!(f, "DATABASE {name}"),
Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
Use::Role(name) => write!(f, "ROLE {name}"),
Use::SecondaryRoles(secondary_roles) => {
write!(f, "SECONDARY ROLES {secondary_roles}")
}
Use::Object(name) => write!(f, "{name}"),
Use::Default => write!(f, "DEFAULT"),
}
}
}
/// Snowflake `SECONDARY ROLES` USE variant
/// See: <https://docs.snowflake.com/en/sql-reference/sql/use-secondary-roles>
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SecondaryRoles {
All,
None,
List(Vec<Ident>),
}
impl fmt::Display for SecondaryRoles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SecondaryRoles::All => write!(f, "ALL"),
SecondaryRoles::None => write!(f, "NONE"),
SecondaryRoles::List(roles) => write!(f, "{}", display_comma_separated(roles)),
}
}
}

2526
src/ast/ddl.rs Normal file

File diff suppressed because it is too large Load diff

709
src/ast/dml.rs Normal file
View file

@ -0,0 +1,709 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::{
boxed::Box,
format,
string::{String, ToString},
vec::Vec,
};
use core::fmt::{self, Display};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use crate::display_utils::{indented_list, DisplayCommaSeparated, Indent, NewLine, SpaceOrNewline};
pub use super::ddl::{ColumnDef, TableConstraint};
use super::{
display_comma_separated, display_separated, query::InputFormatClause, Assignment, ClusteredBy,
CommentDef, CreateTableOptions, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat,
HiveIOFormat, HiveRowFormat, Ident, IndexType, InsertAliases, MysqlInsertPriority, ObjectName,
OnCommit, OnInsert, OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem,
Setting, SqliteOnConflict, StorageSerializationPolicy, TableObject, TableWithJoins, Tag,
WrappedCollection,
};
/// Index column type.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct IndexColumn {
pub column: OrderByExpr,
pub operator_class: Option<Ident>,
}
impl Display for IndexColumn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.column)?;
if let Some(operator_class) = &self.operator_class {
write!(f, " {operator_class}")?;
}
Ok(())
}
}
/// CREATE INDEX statement.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateIndex {
/// index name
pub name: Option<ObjectName>,
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub table_name: ObjectName,
pub using: Option<IndexType>,
pub columns: Vec<IndexColumn>,
pub unique: bool,
pub concurrently: bool,
pub if_not_exists: bool,
pub include: Vec<Ident>,
pub nulls_distinct: Option<bool>,
/// WITH clause: <https://www.postgresql.org/docs/current/sql-createindex.html>
pub with: Vec<Expr>,
pub predicate: Option<Expr>,
}
impl Display for CreateIndex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CREATE {unique}INDEX {concurrently}{if_not_exists}",
unique = if self.unique { "UNIQUE " } else { "" },
concurrently = if self.concurrently {
"CONCURRENTLY "
} else {
""
},
if_not_exists = if self.if_not_exists {
"IF NOT EXISTS "
} else {
""
},
)?;
if let Some(value) = &self.name {
write!(f, "{value} ")?;
}
write!(f, "ON {}", self.table_name)?;
if let Some(value) = &self.using {
write!(f, " USING {value} ")?;
}
write!(f, "({})", display_separated(&self.columns, ","))?;
if !self.include.is_empty() {
write!(f, " INCLUDE ({})", display_separated(&self.include, ","))?;
}
if let Some(value) = self.nulls_distinct {
if value {
write!(f, " NULLS DISTINCT")?;
} else {
write!(f, " NULLS NOT DISTINCT")?;
}
}
if !self.with.is_empty() {
write!(f, " WITH ({})", display_comma_separated(&self.with))?;
}
if let Some(predicate) = &self.predicate {
write!(f, " WHERE {predicate}")?;
}
Ok(())
}
}
/// CREATE TABLE statement.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateTable {
pub or_replace: bool,
pub temporary: bool,
pub external: bool,
pub global: Option<bool>,
pub if_not_exists: bool,
pub transient: bool,
pub volatile: bool,
pub iceberg: bool,
/// Table name
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub name: ObjectName,
/// Optional schema
pub columns: Vec<ColumnDef>,
pub constraints: Vec<TableConstraint>,
pub hive_distribution: HiveDistributionStyle,
pub hive_formats: Option<HiveFormat>,
pub table_options: CreateTableOptions,
pub file_format: Option<FileFormat>,
pub location: Option<String>,
pub query: Option<Box<Query>>,
pub without_rowid: bool,
pub like: Option<ObjectName>,
pub clone: Option<ObjectName>,
// For Hive dialect, the table comment is after the column definitions without `=`,
// so the `comment` field is optional and different than the comment field in the general options list.
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
pub comment: Option<CommentDef>,
pub on_commit: Option<OnCommit>,
/// ClickHouse "ON CLUSTER" clause:
/// <https://clickhouse.com/docs/en/sql-reference/distributed-ddl/>
pub on_cluster: Option<Ident>,
/// ClickHouse "PRIMARY KEY " clause.
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
pub primary_key: Option<Box<Expr>>,
/// ClickHouse "ORDER BY " clause. Note that omitted ORDER BY is different
/// than empty (represented as ()), the latter meaning "no sorting".
/// <https://clickhouse.com/docs/en/sql-reference/statements/create/table/>
pub order_by: Option<OneOrManyWithParens<Expr>>,
/// BigQuery: A partition expression for the table.
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#partition_expression>
pub partition_by: Option<Box<Expr>>,
/// BigQuery: Table clustering column list.
/// <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#table_option_list>
/// Snowflake: Table clustering list which contains base column, expressions on base columns.
/// <https://docs.snowflake.com/en/user-guide/tables-clustering-keys#defining-a-clustering-key-for-a-table>
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
/// Hive: Table clustering column list.
/// <https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable>
pub clustered_by: Option<ClusteredBy>,
/// Postgres `INHERITs` clause, which contains the list of tables from which
/// the new table inherits.
/// <https://www.postgresql.org/docs/current/ddl-inherit.html>
/// <https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-INHERITS>
pub inherits: Option<Vec<ObjectName>>,
/// SQLite "STRICT" clause.
/// if the "STRICT" table-option keyword is added to the end, after the closing ")",
/// then strict typing rules apply to that table.
pub strict: bool,
/// Snowflake "COPY GRANTS" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub copy_grants: bool,
/// Snowflake "ENABLE_SCHEMA_EVOLUTION" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub enable_schema_evolution: Option<bool>,
/// Snowflake "CHANGE_TRACKING" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub change_tracking: Option<bool>,
/// Snowflake "DATA_RETENTION_TIME_IN_DAYS" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub data_retention_time_in_days: Option<u64>,
/// Snowflake "MAX_DATA_EXTENSION_TIME_IN_DAYS" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub max_data_extension_time_in_days: Option<u64>,
/// Snowflake "DEFAULT_DDL_COLLATION" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub default_ddl_collation: Option<String>,
/// Snowflake "WITH AGGREGATION POLICY" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub with_aggregation_policy: Option<ObjectName>,
/// Snowflake "WITH ROW ACCESS POLICY" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub with_row_access_policy: Option<RowAccessPolicy>,
/// Snowflake "WITH TAG" clause
/// <https://docs.snowflake.com/en/sql-reference/sql/create-table>
pub with_tags: Option<Vec<Tag>>,
/// Snowflake "EXTERNAL_VOLUME" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
pub external_volume: Option<String>,
/// Snowflake "BASE_LOCATION" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
pub base_location: Option<String>,
/// Snowflake "CATALOG" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
pub catalog: Option<String>,
/// Snowflake "CATALOG_SYNC" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
pub catalog_sync: Option<String>,
/// Snowflake "STORAGE_SERIALIZATION_POLICY" clause for Iceberg tables
/// <https://docs.snowflake.com/en/sql-reference/sql/create-iceberg-table>
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
}
impl Display for CreateTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// We want to allow the following options
// Empty column list, allowed by PostgreSQL:
// `CREATE TABLE t ()`
// No columns provided for CREATE TABLE AS:
// `CREATE TABLE t AS SELECT a from t2`
// Columns provided for CREATE TABLE AS:
// `CREATE TABLE t (a INT) AS SELECT a from t2`
write!(
f,
"CREATE {or_replace}{external}{global}{temporary}{transient}{volatile}{iceberg}TABLE {if_not_exists}{name}",
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
external = if self.external { "EXTERNAL " } else { "" },
global = self.global
.map(|global| {
if global {
"GLOBAL "
} else {
"LOCAL "
}
})
.unwrap_or(""),
if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
temporary = if self.temporary { "TEMPORARY " } else { "" },
transient = if self.transient { "TRANSIENT " } else { "" },
volatile = if self.volatile { "VOLATILE " } else { "" },
// Only for Snowflake
iceberg = if self.iceberg { "ICEBERG " } else { "" },
name = self.name,
)?;
if let Some(on_cluster) = &self.on_cluster {
write!(f, " ON CLUSTER {on_cluster}")?;
}
if !self.columns.is_empty() || !self.constraints.is_empty() {
f.write_str(" (")?;
NewLine.fmt(f)?;
Indent(DisplayCommaSeparated(&self.columns)).fmt(f)?;
if !self.columns.is_empty() && !self.constraints.is_empty() {
f.write_str(",")?;
SpaceOrNewline.fmt(f)?;
}
Indent(DisplayCommaSeparated(&self.constraints)).fmt(f)?;
NewLine.fmt(f)?;
f.write_str(")")?;
} else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
f.write_str(" ()")?;
}
// Hive table comment should be after column definitions, please refer to:
// [Hive](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-CreateTable)
if let Some(comment) = &self.comment {
write!(f, " COMMENT '{comment}'")?;
}
// Only for SQLite
if self.without_rowid {
write!(f, " WITHOUT ROWID")?;
}
// Only for Hive
if let Some(l) = &self.like {
write!(f, " LIKE {l}")?;
}
if let Some(c) = &self.clone {
write!(f, " CLONE {c}")?;
}
match &self.hive_distribution {
HiveDistributionStyle::PARTITIONED { columns } => {
write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
}
HiveDistributionStyle::SKEWED {
columns,
on,
stored_as_directories,
} => {
write!(
f,
" SKEWED BY ({})) ON ({})",
display_comma_separated(columns),
display_comma_separated(on)
)?;
if *stored_as_directories {
write!(f, " STORED AS DIRECTORIES")?;
}
}
_ => (),
}
if let Some(clustered_by) = &self.clustered_by {
write!(f, " {clustered_by}")?;
}
if let Some(HiveFormat {
row_format,
serde_properties,
storage,
location,
}) = &self.hive_formats
{
match row_format {
Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
Some(HiveRowFormat::DELIMITED { delimiters }) => {
write!(f, " ROW FORMAT DELIMITED")?;
if !delimiters.is_empty() {
write!(f, " {}", display_separated(delimiters, " "))?;
}
}
None => (),
}
match storage {
Some(HiveIOFormat::IOF {
input_format,
output_format,
}) => write!(
f,
" STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
)?,
Some(HiveIOFormat::FileFormat { format }) if !self.external => {
write!(f, " STORED AS {format}")?
}
_ => (),
}
if let Some(serde_properties) = serde_properties.as_ref() {
write!(
f,
" WITH SERDEPROPERTIES ({})",
display_comma_separated(serde_properties)
)?;
}
if !self.external {
if let Some(loc) = location {
write!(f, " LOCATION '{loc}'")?;
}
}
}
if self.external {
if let Some(file_format) = self.file_format {
write!(f, " STORED AS {file_format}")?;
}
write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
}
match &self.table_options {
options @ CreateTableOptions::With(_)
| options @ CreateTableOptions::Plain(_)
| options @ CreateTableOptions::TableProperties(_) => write!(f, " {options}")?,
_ => (),
}
if let Some(primary_key) = &self.primary_key {
write!(f, " PRIMARY KEY {primary_key}")?;
}
if let Some(order_by) = &self.order_by {
write!(f, " ORDER BY {order_by}")?;
}
if let Some(inherits) = &self.inherits {
write!(f, " INHERITS ({})", display_comma_separated(inherits))?;
}
if let Some(partition_by) = self.partition_by.as_ref() {
write!(f, " PARTITION BY {partition_by}")?;
}
if let Some(cluster_by) = self.cluster_by.as_ref() {
write!(f, " CLUSTER BY {cluster_by}")?;
}
if let options @ CreateTableOptions::Options(_) = &self.table_options {
write!(f, " {options}")?;
}
if let Some(external_volume) = self.external_volume.as_ref() {
write!(f, " EXTERNAL_VOLUME = '{external_volume}'")?;
}
if let Some(catalog) = self.catalog.as_ref() {
write!(f, " CATALOG = '{catalog}'")?;
}
if self.iceberg {
if let Some(base_location) = self.base_location.as_ref() {
write!(f, " BASE_LOCATION = '{base_location}'")?;
}
}
if let Some(catalog_sync) = self.catalog_sync.as_ref() {
write!(f, " CATALOG_SYNC = '{catalog_sync}'")?;
}
if let Some(storage_serialization_policy) = self.storage_serialization_policy.as_ref() {
write!(
f,
" STORAGE_SERIALIZATION_POLICY = {storage_serialization_policy}"
)?;
}
if self.copy_grants {
write!(f, " COPY GRANTS")?;
}
if let Some(is_enabled) = self.enable_schema_evolution {
write!(
f,
" ENABLE_SCHEMA_EVOLUTION={}",
if is_enabled { "TRUE" } else { "FALSE" }
)?;
}
if let Some(is_enabled) = self.change_tracking {
write!(
f,
" CHANGE_TRACKING={}",
if is_enabled { "TRUE" } else { "FALSE" }
)?;
}
if let Some(data_retention_time_in_days) = self.data_retention_time_in_days {
write!(
f,
" DATA_RETENTION_TIME_IN_DAYS={data_retention_time_in_days}",
)?;
}
if let Some(max_data_extension_time_in_days) = self.max_data_extension_time_in_days {
write!(
f,
" MAX_DATA_EXTENSION_TIME_IN_DAYS={max_data_extension_time_in_days}",
)?;
}
if let Some(default_ddl_collation) = &self.default_ddl_collation {
write!(f, " DEFAULT_DDL_COLLATION='{default_ddl_collation}'",)?;
}
if let Some(with_aggregation_policy) = &self.with_aggregation_policy {
write!(f, " WITH AGGREGATION POLICY {with_aggregation_policy}",)?;
}
if let Some(row_access_policy) = &self.with_row_access_policy {
write!(f, " {row_access_policy}",)?;
}
if let Some(tag) = &self.with_tags {
write!(f, " WITH TAG ({})", display_comma_separated(tag.as_slice()))?;
}
if self.on_commit.is_some() {
let on_commit = match self.on_commit {
Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
Some(OnCommit::Drop) => "ON COMMIT DROP",
None => "",
};
write!(f, " {on_commit}")?;
}
if self.strict {
write!(f, " STRICT")?;
}
if let Some(query) = &self.query {
write!(f, " AS {query}")?;
}
Ok(())
}
}
/// INSERT statement.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Insert {
/// Only for Sqlite
pub or: Option<SqliteOnConflict>,
/// Only for mysql
pub ignore: bool,
/// INTO - optional keyword
pub into: bool,
/// TABLE
pub table: TableObject,
/// table_name as foo (for PostgreSQL)
pub table_alias: Option<Ident>,
/// COLUMNS
pub columns: Vec<Ident>,
/// Overwrite (Hive)
pub overwrite: bool,
/// A SQL query that specifies what to insert
pub source: Option<Box<Query>>,
/// MySQL `INSERT INTO ... SET`
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
pub assignments: Vec<Assignment>,
/// partitioned insert (Hive)
pub partitioned: Option<Vec<Expr>>,
/// Columns defined after PARTITION
pub after_columns: Vec<Ident>,
/// whether the insert has the table keyword (Hive)
pub has_table_keyword: bool,
pub on: Option<OnInsert>,
/// RETURNING
pub returning: Option<Vec<SelectItem>>,
/// Only for mysql
pub replace_into: bool,
/// Only for mysql
pub priority: Option<MysqlInsertPriority>,
/// Only for mysql
pub insert_alias: Option<InsertAliases>,
/// Settings used for ClickHouse.
///
/// ClickHouse syntax: `INSERT INTO tbl SETTINGS format_template_resultset = '/some/path/resultset.format'`
///
/// [ClickHouse `INSERT INTO`](https://clickhouse.com/docs/en/sql-reference/statements/insert-into)
pub settings: Option<Vec<Setting>>,
/// Format for `INSERT` statement when not using standard SQL format. Can be e.g. `CSV`,
/// `JSON`, `JSONAsString`, `LineAsString` and more.
///
/// ClickHouse syntax: `INSERT INTO tbl FORMAT JSONEachRow {"foo": 1, "bar": 2}, {"foo": 3}`
///
/// [ClickHouse formats JSON insert](https://clickhouse.com/docs/en/interfaces/formats#json-inserting-data)
pub format_clause: Option<InputFormatClause>,
}
impl Display for Insert {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let table_name = if let Some(alias) = &self.table_alias {
format!("{0} AS {alias}", self.table)
} else {
self.table.to_string()
};
if let Some(on_conflict) = self.or {
write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
} else {
write!(
f,
"{start}",
start = if self.replace_into {
"REPLACE"
} else {
"INSERT"
},
)?;
if let Some(priority) = self.priority {
write!(f, " {priority}",)?;
}
write!(
f,
"{ignore}{over}{int}{tbl} {table_name} ",
table_name = table_name,
ignore = if self.ignore { " IGNORE" } else { "" },
over = if self.overwrite { " OVERWRITE" } else { "" },
int = if self.into { " INTO" } else { "" },
tbl = if self.has_table_keyword { " TABLE" } else { "" },
)?;
}
if !self.columns.is_empty() {
write!(f, "({})", display_comma_separated(&self.columns))?;
SpaceOrNewline.fmt(f)?;
}
if let Some(ref parts) = self.partitioned {
if !parts.is_empty() {
write!(f, "PARTITION ({})", display_comma_separated(parts))?;
SpaceOrNewline.fmt(f)?;
}
}
if !self.after_columns.is_empty() {
write!(f, "({})", display_comma_separated(&self.after_columns))?;
SpaceOrNewline.fmt(f)?;
}
if let Some(settings) = &self.settings {
write!(f, "SETTINGS {}", display_comma_separated(settings))?;
SpaceOrNewline.fmt(f)?;
}
if let Some(source) = &self.source {
source.fmt(f)?;
} else if !self.assignments.is_empty() {
write!(f, "SET")?;
indented_list(f, &self.assignments)?;
} else if let Some(format_clause) = &self.format_clause {
format_clause.fmt(f)?;
} else if self.columns.is_empty() {
write!(f, "DEFAULT VALUES")?;
}
if let Some(insert_alias) = &self.insert_alias {
write!(f, " AS {0}", insert_alias.row_alias)?;
if let Some(col_aliases) = &insert_alias.col_aliases {
if !col_aliases.is_empty() {
write!(f, " ({})", display_comma_separated(col_aliases))?;
}
}
}
if let Some(on) = &self.on {
write!(f, "{on}")?;
}
if let Some(returning) = &self.returning {
SpaceOrNewline.fmt(f)?;
f.write_str("RETURNING")?;
indented_list(f, returning)?;
}
Ok(())
}
}
/// DELETE statement.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Delete {
/// Multi tables delete are supported in mysql
pub tables: Vec<ObjectName>,
/// FROM
pub from: FromTable,
/// USING (Snowflake, Postgres, MySQL)
pub using: Option<Vec<TableWithJoins>>,
/// WHERE
pub selection: Option<Expr>,
/// RETURNING
pub returning: Option<Vec<SelectItem>>,
/// ORDER BY (MySQL)
pub order_by: Vec<OrderByExpr>,
/// LIMIT (MySQL)
pub limit: Option<Expr>,
}
impl Display for Delete {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("DELETE")?;
if !self.tables.is_empty() {
indented_list(f, &self.tables)?;
}
match &self.from {
FromTable::WithFromKeyword(from) => {
f.write_str(" FROM")?;
indented_list(f, from)?;
}
FromTable::WithoutKeyword(from) => {
indented_list(f, from)?;
}
}
if let Some(using) = &self.using {
SpaceOrNewline.fmt(f)?;
f.write_str("USING")?;
indented_list(f, using)?;
}
if let Some(selection) = &self.selection {
SpaceOrNewline.fmt(f)?;
f.write_str("WHERE")?;
SpaceOrNewline.fmt(f)?;
Indent(selection).fmt(f)?;
}
if let Some(returning) = &self.returning {
SpaceOrNewline.fmt(f)?;
f.write_str("RETURNING")?;
indented_list(f, returning)?;
}
if !self.order_by.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("ORDER BY")?;
indented_list(f, &self.order_by)?;
}
if let Some(limit) = &self.limit {
SpaceOrNewline.fmt(f)?;
f.write_str("LIMIT")?;
SpaceOrNewline.fmt(f)?;
Indent(limit).fmt(f)?;
}
Ok(())
}
}

View file

@ -0,0 +1,136 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::fmt::{self, Debug, Formatter};
use core::hash::{Hash, Hasher};
use crate::tokenizer::TokenWithSpan;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
/// A wrapper over [`TokenWithSpan`]s that ignores the token and source
/// location in comparisons and hashing.
///
/// This type is used when the token and location is not relevant for semantics,
/// but is still needed for accurate source location tracking, for example, in
/// the nodes in the [ast](crate::ast) module.
///
/// Note: **All** `AttachedTokens` are equal.
///
/// # Examples
///
/// Same token, different location are equal
/// ```
/// # use sqlparser::ast::helpers::attached_token::AttachedToken;
/// # use sqlparser::tokenizer::{Location, Span, Token, TokenWithLocation};
/// // commas @ line 1, column 10
/// let tok1 = TokenWithLocation::new(
/// Token::Comma,
/// Span::new(Location::new(1, 10), Location::new(1, 11)),
/// );
/// // commas @ line 2, column 20
/// let tok2 = TokenWithLocation::new(
/// Token::Comma,
/// Span::new(Location::new(2, 20), Location::new(2, 21)),
/// );
///
/// assert_ne!(tok1, tok2); // token with locations are *not* equal
/// assert_eq!(AttachedToken(tok1), AttachedToken(tok2)); // attached tokens are
/// ```
///
/// Different token, different location are equal 🤯
///
/// ```
/// # use sqlparser::ast::helpers::attached_token::AttachedToken;
/// # use sqlparser::tokenizer::{Location, Span, Token, TokenWithLocation};
/// // commas @ line 1, column 10
/// let tok1 = TokenWithLocation::new(
/// Token::Comma,
/// Span::new(Location::new(1, 10), Location::new(1, 11)),
/// );
/// // period @ line 2, column 20
/// let tok2 = TokenWithLocation::new(
/// Token::Period,
/// Span::new(Location::new(2, 10), Location::new(2, 21)),
/// );
///
/// assert_ne!(tok1, tok2); // token with locations are *not* equal
/// assert_eq!(AttachedToken(tok1), AttachedToken(tok2)); // attached tokens are
/// ```
/// // period @ line 2, column 20
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct AttachedToken(pub TokenWithSpan);
impl AttachedToken {
/// Return a new Empty AttachedToken
pub fn empty() -> Self {
AttachedToken(TokenWithSpan::new_eof())
}
}
// Conditional Implementations
impl Debug for AttachedToken {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
// Blanket Implementations
impl PartialEq for AttachedToken {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl Eq for AttachedToken {}
impl PartialOrd for AttachedToken {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AttachedToken {
fn cmp(&self, _: &Self) -> Ordering {
Ordering::Equal
}
}
impl Hash for AttachedToken {
fn hash<H: Hasher>(&self, _state: &mut H) {
// Do nothing
}
}
impl From<TokenWithSpan> for AttachedToken {
fn from(value: TokenWithSpan) -> Self {
AttachedToken(value)
}
}
impl From<AttachedToken> for TokenWithSpan {
fn from(value: AttachedToken) -> Self {
value.0
}
}

View file

@ -0,0 +1,89 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! Key-value options for SQL statements.
//! See [this page](https://docs.snowflake.com/en/sql-reference/commands-data-loading) for more details.
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
use core::fmt::Formatter;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct KeyValueOptions {
pub options: Vec<KeyValueOption>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum KeyValueOptionType {
STRING,
BOOLEAN,
ENUM,
NUMBER,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct KeyValueOption {
pub option_name: String,
pub option_type: KeyValueOptionType,
pub value: String,
}
impl fmt::Display for KeyValueOptions {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if !self.options.is_empty() {
let mut first = false;
for option in &self.options {
if !first {
first = true;
} else {
f.write_str(" ")?;
}
write!(f, "{option}")?;
}
}
Ok(())
}
}
impl fmt::Display for KeyValueOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.option_type {
KeyValueOptionType::STRING => {
write!(f, "{}='{}'", self.option_name, self.value)?;
}
KeyValueOptionType::ENUM | KeyValueOptionType::BOOLEAN | KeyValueOptionType::NUMBER => {
write!(f, "{}={}", self.option_name, self.value)?;
}
}
Ok(())
}
}

20
src/ast/helpers/mod.rs Normal file
View file

@ -0,0 +1,20 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
pub mod attached_token;
pub mod key_value_options;
pub mod stmt_create_table;
pub mod stmt_data_loading;

View file

@ -0,0 +1,580 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use super::super::dml::CreateTable;
use crate::ast::{
ClusteredBy, ColumnDef, CommentDef, CreateTableOptions, Expr, FileFormat,
HiveDistributionStyle, HiveFormat, Ident, ObjectName, OnCommit, OneOrManyWithParens, Query,
RowAccessPolicy, Statement, StorageSerializationPolicy, TableConstraint, Tag,
WrappedCollection,
};
use crate::parser::ParserError;
/// Builder for create table statement variant ([1]).
///
/// This structure helps building and accessing a create table with more ease, without needing to:
/// - Match the enum itself a lot of times; or
/// - Moving a lot of variables around the code.
///
/// # Example
/// ```rust
/// use sqlparser::ast::helpers::stmt_create_table::CreateTableBuilder;
/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName};
/// let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]))
/// .if_not_exists(true)
/// .columns(vec![ColumnDef {
/// name: Ident::new("c1"),
/// data_type: DataType::Int(None),
/// options: vec![],
/// }]);
/// // You can access internal elements with ease
/// assert!(builder.if_not_exists);
/// // Convert to a statement
/// assert_eq!(
/// builder.build().to_string(),
/// "CREATE TABLE IF NOT EXISTS table_name (c1 INT)"
/// )
/// ```
///
/// [1]: crate::ast::Statement::CreateTable
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateTableBuilder {
pub or_replace: bool,
pub temporary: bool,
pub external: bool,
pub global: Option<bool>,
pub if_not_exists: bool,
pub transient: bool,
pub volatile: bool,
pub iceberg: bool,
pub name: ObjectName,
pub columns: Vec<ColumnDef>,
pub constraints: Vec<TableConstraint>,
pub hive_distribution: HiveDistributionStyle,
pub hive_formats: Option<HiveFormat>,
pub file_format: Option<FileFormat>,
pub location: Option<String>,
pub query: Option<Box<Query>>,
pub without_rowid: bool,
pub like: Option<ObjectName>,
pub clone: Option<ObjectName>,
pub comment: Option<CommentDef>,
pub on_commit: Option<OnCommit>,
pub on_cluster: Option<Ident>,
pub primary_key: Option<Box<Expr>>,
pub order_by: Option<OneOrManyWithParens<Expr>>,
pub partition_by: Option<Box<Expr>>,
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
pub clustered_by: Option<ClusteredBy>,
pub inherits: Option<Vec<ObjectName>>,
pub strict: bool,
pub copy_grants: bool,
pub enable_schema_evolution: Option<bool>,
pub change_tracking: Option<bool>,
pub data_retention_time_in_days: Option<u64>,
pub max_data_extension_time_in_days: Option<u64>,
pub default_ddl_collation: Option<String>,
pub with_aggregation_policy: Option<ObjectName>,
pub with_row_access_policy: Option<RowAccessPolicy>,
pub with_tags: Option<Vec<Tag>>,
pub base_location: Option<String>,
pub external_volume: Option<String>,
pub catalog: Option<String>,
pub catalog_sync: Option<String>,
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
pub table_options: CreateTableOptions,
}
impl CreateTableBuilder {
pub fn new(name: ObjectName) -> Self {
Self {
or_replace: false,
temporary: false,
external: false,
global: None,
if_not_exists: false,
transient: false,
volatile: false,
iceberg: false,
name,
columns: vec![],
constraints: vec![],
hive_distribution: HiveDistributionStyle::NONE,
hive_formats: None,
file_format: None,
location: None,
query: None,
without_rowid: false,
like: None,
clone: None,
comment: None,
on_commit: None,
on_cluster: None,
primary_key: None,
order_by: None,
partition_by: None,
cluster_by: None,
clustered_by: None,
inherits: None,
strict: false,
copy_grants: false,
enable_schema_evolution: None,
change_tracking: None,
data_retention_time_in_days: None,
max_data_extension_time_in_days: None,
default_ddl_collation: None,
with_aggregation_policy: None,
with_row_access_policy: None,
with_tags: None,
base_location: None,
external_volume: None,
catalog: None,
catalog_sync: None,
storage_serialization_policy: None,
table_options: CreateTableOptions::None,
}
}
pub fn or_replace(mut self, or_replace: bool) -> Self {
self.or_replace = or_replace;
self
}
pub fn temporary(mut self, temporary: bool) -> Self {
self.temporary = temporary;
self
}
pub fn external(mut self, external: bool) -> Self {
self.external = external;
self
}
pub fn global(mut self, global: Option<bool>) -> Self {
self.global = global;
self
}
pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
self.if_not_exists = if_not_exists;
self
}
pub fn transient(mut self, transient: bool) -> Self {
self.transient = transient;
self
}
pub fn volatile(mut self, volatile: bool) -> Self {
self.volatile = volatile;
self
}
pub fn iceberg(mut self, iceberg: bool) -> Self {
self.iceberg = iceberg;
self
}
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
self.columns = columns;
self
}
pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
self.constraints = constraints;
self
}
pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
self.hive_distribution = hive_distribution;
self
}
pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
self.hive_formats = hive_formats;
self
}
pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
self.file_format = file_format;
self
}
pub fn location(mut self, location: Option<String>) -> Self {
self.location = location;
self
}
pub fn query(mut self, query: Option<Box<Query>>) -> Self {
self.query = query;
self
}
pub fn without_rowid(mut self, without_rowid: bool) -> Self {
self.without_rowid = without_rowid;
self
}
pub fn like(mut self, like: Option<ObjectName>) -> Self {
self.like = like;
self
}
// Different name to allow the object to be cloned
pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
self.clone = clone;
self
}
pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
self.comment = comment;
self
}
pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
self.on_commit = on_commit;
self
}
pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
self.on_cluster = on_cluster;
self
}
pub fn primary_key(mut self, primary_key: Option<Box<Expr>>) -> Self {
self.primary_key = primary_key;
self
}
pub fn order_by(mut self, order_by: Option<OneOrManyWithParens<Expr>>) -> Self {
self.order_by = order_by;
self
}
pub fn partition_by(mut self, partition_by: Option<Box<Expr>>) -> Self {
self.partition_by = partition_by;
self
}
pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
self.cluster_by = cluster_by;
self
}
pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
self.clustered_by = clustered_by;
self
}
pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
self.inherits = inherits;
self
}
pub fn strict(mut self, strict: bool) -> Self {
self.strict = strict;
self
}
pub fn copy_grants(mut self, copy_grants: bool) -> Self {
self.copy_grants = copy_grants;
self
}
pub fn enable_schema_evolution(mut self, enable_schema_evolution: Option<bool>) -> Self {
self.enable_schema_evolution = enable_schema_evolution;
self
}
pub fn change_tracking(mut self, change_tracking: Option<bool>) -> Self {
self.change_tracking = change_tracking;
self
}
pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
self.data_retention_time_in_days = data_retention_time_in_days;
self
}
pub fn max_data_extension_time_in_days(
mut self,
max_data_extension_time_in_days: Option<u64>,
) -> Self {
self.max_data_extension_time_in_days = max_data_extension_time_in_days;
self
}
pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
self.default_ddl_collation = default_ddl_collation;
self
}
pub fn with_aggregation_policy(mut self, with_aggregation_policy: Option<ObjectName>) -> Self {
self.with_aggregation_policy = with_aggregation_policy;
self
}
pub fn with_row_access_policy(
mut self,
with_row_access_policy: Option<RowAccessPolicy>,
) -> Self {
self.with_row_access_policy = with_row_access_policy;
self
}
pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
self.with_tags = with_tags;
self
}
pub fn base_location(mut self, base_location: Option<String>) -> Self {
self.base_location = base_location;
self
}
pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
self.external_volume = external_volume;
self
}
pub fn catalog(mut self, catalog: Option<String>) -> Self {
self.catalog = catalog;
self
}
pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
self.catalog_sync = catalog_sync;
self
}
pub fn storage_serialization_policy(
mut self,
storage_serialization_policy: Option<StorageSerializationPolicy>,
) -> Self {
self.storage_serialization_policy = storage_serialization_policy;
self
}
pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
self.table_options = table_options;
self
}
pub fn build(self) -> Statement {
Statement::CreateTable(CreateTable {
or_replace: self.or_replace,
temporary: self.temporary,
external: self.external,
global: self.global,
if_not_exists: self.if_not_exists,
transient: self.transient,
volatile: self.volatile,
iceberg: self.iceberg,
name: self.name,
columns: self.columns,
constraints: self.constraints,
hive_distribution: self.hive_distribution,
hive_formats: self.hive_formats,
file_format: self.file_format,
location: self.location,
query: self.query,
without_rowid: self.without_rowid,
like: self.like,
clone: self.clone,
comment: self.comment,
on_commit: self.on_commit,
on_cluster: self.on_cluster,
primary_key: self.primary_key,
order_by: self.order_by,
partition_by: self.partition_by,
cluster_by: self.cluster_by,
clustered_by: self.clustered_by,
inherits: self.inherits,
strict: self.strict,
copy_grants: self.copy_grants,
enable_schema_evolution: self.enable_schema_evolution,
change_tracking: self.change_tracking,
data_retention_time_in_days: self.data_retention_time_in_days,
max_data_extension_time_in_days: self.max_data_extension_time_in_days,
default_ddl_collation: self.default_ddl_collation,
with_aggregation_policy: self.with_aggregation_policy,
with_row_access_policy: self.with_row_access_policy,
with_tags: self.with_tags,
base_location: self.base_location,
external_volume: self.external_volume,
catalog: self.catalog,
catalog_sync: self.catalog_sync,
storage_serialization_policy: self.storage_serialization_policy,
table_options: self.table_options,
})
}
}
impl TryFrom<Statement> for CreateTableBuilder {
type Error = ParserError;
// As the builder can be transformed back to a statement, it shouldn't be a problem to take the
// ownership.
fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
match stmt {
Statement::CreateTable(CreateTable {
or_replace,
temporary,
external,
global,
if_not_exists,
transient,
volatile,
iceberg,
name,
columns,
constraints,
hive_distribution,
hive_formats,
file_format,
location,
query,
without_rowid,
like,
clone,
comment,
on_commit,
on_cluster,
primary_key,
order_by,
partition_by,
cluster_by,
clustered_by,
inherits,
strict,
copy_grants,
enable_schema_evolution,
change_tracking,
data_retention_time_in_days,
max_data_extension_time_in_days,
default_ddl_collation,
with_aggregation_policy,
with_row_access_policy,
with_tags,
base_location,
external_volume,
catalog,
catalog_sync,
storage_serialization_policy,
table_options,
}) => Ok(Self {
or_replace,
temporary,
external,
global,
if_not_exists,
transient,
name,
columns,
constraints,
hive_distribution,
hive_formats,
file_format,
location,
query,
without_rowid,
like,
clone,
comment,
on_commit,
on_cluster,
primary_key,
order_by,
partition_by,
cluster_by,
clustered_by,
inherits,
strict,
iceberg,
copy_grants,
enable_schema_evolution,
change_tracking,
data_retention_time_in_days,
max_data_extension_time_in_days,
default_ddl_collation,
with_aggregation_policy,
with_row_access_policy,
with_tags,
volatile,
base_location,
external_volume,
catalog,
catalog_sync,
storage_serialization_policy,
table_options,
}),
_ => Err(ParserError::ParserError(format!(
"Expected create table statement, but received: {stmt}"
))),
}
}
}
/// Helper return type when parsing configuration for a `CREATE TABLE` statement.
#[derive(Default)]
pub(crate) struct CreateTableConfiguration {
pub partition_by: Option<Box<Expr>>,
pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
pub inherits: Option<Vec<ObjectName>>,
pub table_options: CreateTableOptions,
}
#[cfg(test)]
mod tests {
use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
use crate::ast::{Ident, ObjectName, Statement};
use crate::parser::ParserError;
#[test]
pub fn test_from_valid_statement() {
let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
let stmt = builder.clone().build();
assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
}
#[test]
pub fn test_from_invalid_statement() {
let stmt = Statement::Commit {
chain: false,
end: false,
modifier: None,
};
assert_eq!(
CreateTableBuilder::try_from(stmt).unwrap_err(),
ParserError::ParserError(
"Expected create table statement, but received: COMMIT".to_owned()
)
);
}
}

View file

@ -0,0 +1,133 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! AST types specific to loading and unloading syntax, like one available in Snowflake which
//! contains: STAGE ddl operations, PUT upload or COPY INTO
//! See [this page](https://docs.snowflake.com/en/sql-reference/commands-data-loading) for more details.
#[cfg(not(feature = "std"))]
use alloc::string::String;
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::ast::helpers::key_value_options::KeyValueOptions;
use crate::ast::{Ident, ObjectName, SelectItem};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct StageParamsObject {
pub url: Option<String>,
pub encryption: KeyValueOptions,
pub endpoint: Option<String>,
pub storage_integration: Option<String>,
pub credentials: KeyValueOptions,
}
/// This enum enables support for both standard SQL select item expressions
/// and Snowflake-specific ones for data loading.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum StageLoadSelectItemKind {
SelectItem(SelectItem),
StageLoadSelectItem(StageLoadSelectItem),
}
impl fmt::Display for StageLoadSelectItemKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
StageLoadSelectItemKind::SelectItem(item) => write!(f, "{item}"),
StageLoadSelectItemKind::StageLoadSelectItem(item) => write!(f, "{item}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct StageLoadSelectItem {
pub alias: Option<Ident>,
pub file_col_num: i32,
pub element: Option<Ident>,
pub item_as: Option<Ident>,
}
impl fmt::Display for StageParamsObject {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let url = &self.url.as_ref();
let storage_integration = &self.storage_integration.as_ref();
let endpoint = &self.endpoint.as_ref();
if url.is_some() {
write!(f, " URL='{}'", url.unwrap())?;
}
if storage_integration.is_some() {
write!(f, " STORAGE_INTEGRATION={}", storage_integration.unwrap())?;
}
if endpoint.is_some() {
write!(f, " ENDPOINT='{}'", endpoint.unwrap())?;
}
if !self.credentials.options.is_empty() {
write!(f, " CREDENTIALS=({})", self.credentials)?;
}
if !self.encryption.options.is_empty() {
write!(f, " ENCRYPTION=({})", self.encryption)?;
}
Ok(())
}
}
impl fmt::Display for StageLoadSelectItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.alias.is_some() {
write!(f, "{}.", self.alias.as_ref().unwrap())?;
}
write!(f, "${}", self.file_col_num)?;
if self.element.is_some() {
write!(f, ":{}", self.element.as_ref().unwrap())?;
}
if self.item_as.is_some() {
write!(f, " AS {}", self.item_as.as_ref().unwrap())?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct FileStagingCommand {
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub stage: ObjectName,
pub pattern: Option<String>,
}
impl fmt::Display for FileStagingCommand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.stage)?;
if let Some(pattern) = self.pattern.as_ref() {
write!(f, " PATTERN='{pattern}'")?;
}
Ok(())
}
}

10319
src/ast/mod.rs Normal file

File diff suppressed because it is too large Load diff

410
src/ast/operator.rs Normal file
View file

@ -0,0 +1,410 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use core::fmt;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use super::display_separated;
/// Unary operators
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum UnaryOperator {
/// Plus, e.g. `+9`
Plus,
/// Minus, e.g. `-9`
Minus,
/// Not, e.g. `NOT(true)`
Not,
/// Bitwise Not, e.g. `~9` (PostgreSQL-specific)
PGBitwiseNot,
/// Square root, e.g. `|/9` (PostgreSQL-specific)
PGSquareRoot,
/// Cube root, e.g. `||/27` (PostgreSQL-specific)
PGCubeRoot,
/// Factorial, e.g. `9!` (PostgreSQL-specific)
PGPostfixFactorial,
/// Factorial, e.g. `!!9` (PostgreSQL-specific)
PGPrefixFactorial,
/// Absolute value, e.g. `@ -9` (PostgreSQL-specific)
PGAbs,
/// Unary logical not operator: e.g. `! false` (Hive-specific)
BangNot,
/// `#` Number of points in path or polygon (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
Hash,
/// `@-@` Length or circumference (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AtDashAt,
/// `@@` Center (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleAt,
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDash,
/// `?|` Is vertical? (PostgreSQL/Redshift geometric operator)
/// see <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionPipe,
}
impl fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match self {
UnaryOperator::Plus => "+",
UnaryOperator::Minus => "-",
UnaryOperator::Not => "NOT",
UnaryOperator::PGBitwiseNot => "~",
UnaryOperator::PGSquareRoot => "|/",
UnaryOperator::PGCubeRoot => "||/",
UnaryOperator::PGPostfixFactorial => "!",
UnaryOperator::PGPrefixFactorial => "!!",
UnaryOperator::PGAbs => "@",
UnaryOperator::BangNot => "!",
UnaryOperator::Hash => "#",
UnaryOperator::AtDashAt => "@-@",
UnaryOperator::DoubleAt => "@@",
UnaryOperator::QuestionDash => "?-",
UnaryOperator::QuestionPipe => "?|",
})
}
}
/// Binary operators
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum BinaryOperator {
/// Plus, e.g. `a + b`
Plus,
/// Minus, e.g. `a - b`
Minus,
/// Multiply, e.g. `a * b`
Multiply,
/// Divide, e.g. `a / b`
Divide,
/// Modulo, e.g. `a % b`
Modulo,
/// String/Array Concat operator, e.g. `a || b`
StringConcat,
/// Greater than, e.g. `a > b`
Gt,
/// Less than, e.g. `a < b`
Lt,
/// Greater equal, e.g. `a >= b`
GtEq,
/// Less equal, e.g. `a <= b`
LtEq,
/// Spaceship, e.g. `a <=> b`
Spaceship,
/// Equal, e.g. `a = b`
Eq,
/// Not equal, e.g. `a <> b`
NotEq,
/// And, e.g. `a AND b`
And,
/// Or, e.g. `a OR b`
Or,
/// XOR, e.g. `a XOR b`
Xor,
/// Bitwise or, e.g. `a | b`
BitwiseOr,
/// Bitwise and, e.g. `a & b`
BitwiseAnd,
/// Bitwise XOR, e.g. `a ^ b`
BitwiseXor,
/// Integer division operator `//` in DuckDB
DuckIntegerDivide,
/// MySQL [`DIV`](https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html) integer division
MyIntegerDivide,
/// MATCH operator, e.g. `a MATCH b` (SQLite-specific)
/// See <https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators>
Match,
/// REGEXP operator, e.g. `a REGEXP b` (SQLite-specific)
Regexp,
/// Support for custom operators (such as Postgres custom operators)
Custom(String),
/// Bitwise XOR, e.g. `a # b` (PostgreSQL-specific)
PGBitwiseXor,
/// Bitwise shift left, e.g. `a << b` (PostgreSQL-specific)
PGBitwiseShiftLeft,
/// Bitwise shift right, e.g. `a >> b` (PostgreSQL-specific)
PGBitwiseShiftRight,
/// Exponent, e.g. `a ^ b` (PostgreSQL-specific)
PGExp,
/// Overlap operator, e.g. `a && b` (PostgreSQL-specific)
PGOverlap,
/// String matches regular expression (case sensitively), e.g. `a ~ b` (PostgreSQL-specific)
PGRegexMatch,
/// String matches regular expression (case insensitively), e.g. `a ~* b` (PostgreSQL-specific)
PGRegexIMatch,
/// String does not match regular expression (case sensitively), e.g. `a !~ b` (PostgreSQL-specific)
PGRegexNotMatch,
/// String does not match regular expression (case insensitively), e.g. `a !~* b` (PostgreSQL-specific)
PGRegexNotIMatch,
/// String matches pattern (case sensitively), e.g. `a ~~ b` (PostgreSQL-specific)
PGLikeMatch,
/// String matches pattern (case insensitively), e.g. `a ~~* b` (PostgreSQL-specific)
PGILikeMatch,
/// String does not match pattern (case sensitively), e.g. `a !~~ b` (PostgreSQL-specific)
PGNotLikeMatch,
/// String does not match pattern (case insensitively), e.g. `a !~~* b` (PostgreSQL-specific)
PGNotILikeMatch,
/// String "starts with", eg: `a ^@ b` (PostgreSQL-specific)
PGStartsWith,
/// The `->` operator.
///
/// On PostgreSQL, this operator extracts a JSON object field or array
/// element, for example `'{"a":"b"}'::json -> 'a'` or `[1, 2, 3]'::json
/// -> 2`.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
Arrow,
/// The `->>` operator.
///
/// On PostgreSQL, this operator extracts a JSON object field or JSON
/// array element and converts it to text, for example `'{"a":"b"}'::json
/// ->> 'a'` or `[1, 2, 3]'::json ->> 2`.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
LongArrow,
/// The `#>` operator.
///
/// On PostgreSQL, this operator extracts a JSON sub-object at the specified
/// path, for example:
///
/// ```notrust
///'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}'
/// ```
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
HashArrow,
/// The `#>>` operator.
///
/// A PostgreSQL-specific operator that extracts JSON sub-object at the
/// specified path, for example
///
/// ```notrust
///'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}'
/// ```
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
HashLongArrow,
/// The `@@` operator.
///
/// On PostgreSQL, this is used for JSON and text searches.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
/// See <https://www.postgresql.org/docs/current/functions-textsearch.html>.
AtAt,
/// The `@>` operator.
///
/// On PostgreSQL, this is used for JSON and text searches.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
/// See <https://www.postgresql.org/docs/current/functions-textsearch.html>.
AtArrow,
/// The `<@` operator.
///
/// On PostgreSQL, this is used for JSON and text searches.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
/// See <https://www.postgresql.org/docs/current/functions-textsearch.html>.
ArrowAt,
/// The `#-` operator.
///
/// On PostgreSQL, this operator is used to delete a field or array element
/// at a specified path.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
HashMinus,
/// The `@?` operator.
///
/// On PostgreSQL, this operator is used to check the given JSON path
/// returns an item for the JSON value.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
AtQuestion,
/// The `?` operator.
///
/// On PostgreSQL, this operator is used to check whether a string exists as a top-level key
/// within the JSON value
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
Question,
/// The `?&` operator.
///
/// On PostgreSQL, this operator is used to check whether all of the the indicated array
/// members exist as top-level keys.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
QuestionAnd,
/// The `?|` operator.
///
/// On PostgreSQL, this operator is used to check whether any of the the indicated array
/// members exist as top-level keys.
///
/// See <https://www.postgresql.org/docs/current/functions-json.html>.
QuestionPipe,
/// PostgreSQL-specific custom operator.
///
/// See [CREATE OPERATOR](https://www.postgresql.org/docs/current/sql-createoperator.html)
/// for more information.
PGCustomBinaryOperator(Vec<String>),
/// The `OVERLAPS` operator
///
/// Specifies a test for an overlap between two datetime periods:
/// <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#overlaps-predicate>
Overlaps,
/// `##` Point of closest proximity (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
DoubleHash,
/// `<->` Distance between (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtDashGt,
/// `&<` Overlaps to left? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndLt,
/// `&>` Overlaps to right? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndGt,
/// `<<|` Is strictly below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtLtPipe,
/// `|>>` Is strictly above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
PipeGtGt,
/// `&<|` Does not extend above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
AndLtPipe,
/// `|&>` Does not extend below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
PipeAndGt,
/// `<^` Is below? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
LtCaret,
/// `>^` Is above? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
GtCaret,
/// `?#` Intersects? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionHash,
/// `?-` Is horizontal? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDash,
/// `?-|` Is perpendicular? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDashPipe,
/// `?||` Are Parallel? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
QuestionDoublePipe,
/// `@` Contained or on? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
At,
/// `~=` Same as? (PostgreSQL/Redshift geometric operator)
/// See <https://www.postgresql.org/docs/9.5/functions-geometry.html>
TildeEq,
/// ':=' Assignment Operator
/// See <https://dev.mysql.com/doc/refman/8.4/en/assignment-operators.html#operator_assign-value>
Assignment,
}
impl fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BinaryOperator::Plus => f.write_str("+"),
BinaryOperator::Minus => f.write_str("-"),
BinaryOperator::Multiply => f.write_str("*"),
BinaryOperator::Divide => f.write_str("/"),
BinaryOperator::Modulo => f.write_str("%"),
BinaryOperator::StringConcat => f.write_str("||"),
BinaryOperator::Gt => f.write_str(">"),
BinaryOperator::Lt => f.write_str("<"),
BinaryOperator::GtEq => f.write_str(">="),
BinaryOperator::LtEq => f.write_str("<="),
BinaryOperator::Spaceship => f.write_str("<=>"),
BinaryOperator::Eq => f.write_str("="),
BinaryOperator::NotEq => f.write_str("<>"),
BinaryOperator::And => f.write_str("AND"),
BinaryOperator::Or => f.write_str("OR"),
BinaryOperator::Xor => f.write_str("XOR"),
BinaryOperator::BitwiseOr => f.write_str("|"),
BinaryOperator::BitwiseAnd => f.write_str("&"),
BinaryOperator::BitwiseXor => f.write_str("^"),
BinaryOperator::DuckIntegerDivide => f.write_str("//"),
BinaryOperator::MyIntegerDivide => f.write_str("DIV"),
BinaryOperator::Match => f.write_str("MATCH"),
BinaryOperator::Regexp => f.write_str("REGEXP"),
BinaryOperator::Custom(s) => f.write_str(s),
BinaryOperator::PGBitwiseXor => f.write_str("#"),
BinaryOperator::PGBitwiseShiftLeft => f.write_str("<<"),
BinaryOperator::PGBitwiseShiftRight => f.write_str(">>"),
BinaryOperator::PGExp => f.write_str("^"),
BinaryOperator::PGOverlap => f.write_str("&&"),
BinaryOperator::PGRegexMatch => f.write_str("~"),
BinaryOperator::PGRegexIMatch => f.write_str("~*"),
BinaryOperator::PGRegexNotMatch => f.write_str("!~"),
BinaryOperator::PGRegexNotIMatch => f.write_str("!~*"),
BinaryOperator::PGLikeMatch => f.write_str("~~"),
BinaryOperator::PGILikeMatch => f.write_str("~~*"),
BinaryOperator::PGNotLikeMatch => f.write_str("!~~"),
BinaryOperator::PGNotILikeMatch => f.write_str("!~~*"),
BinaryOperator::PGStartsWith => f.write_str("^@"),
BinaryOperator::Arrow => f.write_str("->"),
BinaryOperator::LongArrow => f.write_str("->>"),
BinaryOperator::HashArrow => f.write_str("#>"),
BinaryOperator::HashLongArrow => f.write_str("#>>"),
BinaryOperator::AtAt => f.write_str("@@"),
BinaryOperator::AtArrow => f.write_str("@>"),
BinaryOperator::ArrowAt => f.write_str("<@"),
BinaryOperator::HashMinus => f.write_str("#-"),
BinaryOperator::AtQuestion => f.write_str("@?"),
BinaryOperator::Question => f.write_str("?"),
BinaryOperator::QuestionAnd => f.write_str("?&"),
BinaryOperator::QuestionPipe => f.write_str("?|"),
BinaryOperator::PGCustomBinaryOperator(idents) => {
write!(f, "OPERATOR({})", display_separated(idents, "."))
}
BinaryOperator::Overlaps => f.write_str("OVERLAPS"),
BinaryOperator::DoubleHash => f.write_str("##"),
BinaryOperator::LtDashGt => f.write_str("<->"),
BinaryOperator::AndLt => f.write_str("&<"),
BinaryOperator::AndGt => f.write_str("&>"),
BinaryOperator::LtLtPipe => f.write_str("<<|"),
BinaryOperator::PipeGtGt => f.write_str("|>>"),
BinaryOperator::AndLtPipe => f.write_str("&<|"),
BinaryOperator::PipeAndGt => f.write_str("|&>"),
BinaryOperator::LtCaret => f.write_str("<^"),
BinaryOperator::GtCaret => f.write_str(">^"),
BinaryOperator::QuestionHash => f.write_str("?#"),
BinaryOperator::QuestionDash => f.write_str("?-"),
BinaryOperator::QuestionDashPipe => f.write_str("?-|"),
BinaryOperator::QuestionDoublePipe => f.write_str("?||"),
BinaryOperator::At => f.write_str("@"),
BinaryOperator::TildeEq => f.write_str("~="),
BinaryOperator::Assignment => f.write_str(":="),
}
}
}

3661
src/ast/query.rs Normal file

File diff suppressed because it is too large Load diff

2506
src/ast/spans.rs Normal file

File diff suppressed because it is too large Load diff

165
src/ast/trigger.rs Normal file
View file

@ -0,0 +1,165 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! SQL Abstract Syntax Tree (AST) for triggers.
use super::*;
/// This specifies whether the trigger function should be fired once for every row affected by the trigger event, or just once per SQL statement.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TriggerObject {
Row,
Statement,
}
impl fmt::Display for TriggerObject {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TriggerObject::Row => write!(f, "ROW"),
TriggerObject::Statement => write!(f, "STATEMENT"),
}
}
}
/// This clause indicates whether the following relation name is for the before-image transition relation or the after-image transition relation
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TriggerReferencingType {
OldTable,
NewTable,
}
impl fmt::Display for TriggerReferencingType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TriggerReferencingType::OldTable => write!(f, "OLD TABLE"),
TriggerReferencingType::NewTable => write!(f, "NEW TABLE"),
}
}
}
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TriggerReferencing {
pub refer_type: TriggerReferencingType,
pub is_as: bool,
pub transition_relation_name: ObjectName,
}
impl fmt::Display for TriggerReferencing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{refer_type}{is_as} {relation_name}",
refer_type = self.refer_type,
is_as = if self.is_as { " AS" } else { "" },
relation_name = self.transition_relation_name
)
}
}
/// Used to describe trigger events
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TriggerEvent {
Insert,
Update(Vec<Ident>),
Delete,
Truncate,
}
impl fmt::Display for TriggerEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TriggerEvent::Insert => write!(f, "INSERT"),
TriggerEvent::Update(columns) => {
write!(f, "UPDATE")?;
if !columns.is_empty() {
write!(f, " OF")?;
write!(f, " {}", display_comma_separated(columns))?;
}
Ok(())
}
TriggerEvent::Delete => write!(f, "DELETE"),
TriggerEvent::Truncate => write!(f, "TRUNCATE"),
}
}
}
/// Trigger period
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TriggerPeriod {
For,
After,
Before,
InsteadOf,
}
impl fmt::Display for TriggerPeriod {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TriggerPeriod::For => write!(f, "FOR"),
TriggerPeriod::After => write!(f, "AFTER"),
TriggerPeriod::Before => write!(f, "BEFORE"),
TriggerPeriod::InsteadOf => write!(f, "INSTEAD OF"),
}
}
}
/// Types of trigger body execution body.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TriggerExecBodyType {
Function,
Procedure,
}
impl fmt::Display for TriggerExecBodyType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TriggerExecBodyType::Function => write!(f, "FUNCTION"),
TriggerExecBodyType::Procedure => write!(f, "PROCEDURE"),
}
}
}
/// This keyword immediately precedes the declaration of one or two relation names that provide access to the transition relations of the triggering statement
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct TriggerExecBody {
pub exec_type: TriggerExecBodyType,
pub func_desc: FunctionDesc,
}
impl fmt::Display for TriggerExecBody {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{exec_type} {func_desc}",
exec_type = self.exec_type,
func_desc = self.func_desc
)
}
}

593
src/ast/value.rs Normal file
View file

@ -0,0 +1,593 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::string::String;
use core::fmt;
#[cfg(feature = "bigdecimal")]
use bigdecimal::BigDecimal;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{ast::Ident, tokenizer::Span};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
/// Wraps a primitive SQL [`Value`] with its [`Span`] location
///
/// # Example: create a `ValueWithSpan` from a `Value`
/// ```
/// # use sqlparser::ast::{Value, ValueWithSpan};
/// # use sqlparser::tokenizer::{Location, Span};
/// let value = Value::SingleQuotedString(String::from("endpoint"));
/// // from line 1, column 1 to line 1, column 7
/// let span = Span::new(Location::new(1, 1), Location::new(1, 7));
/// let value_with_span = value.with_span(span);
/// ```
///
/// # Example: create a `ValueWithSpan` from a `Value` with an empty span
///
/// You can call [`Value::with_empty_span`] to create a `ValueWithSpan` with an empty span
/// ```
/// # use sqlparser::ast::{Value, ValueWithSpan};
/// # use sqlparser::tokenizer::{Location, Span};
/// let value = Value::SingleQuotedString(String::from("endpoint"));
/// let value_with_span = value.with_empty_span();
/// assert_eq!(value_with_span.span, Span::empty());
/// ```
///
/// You can also use the [`From`] trait to convert `ValueWithSpan` to/from `Value`s
/// ```
/// # use sqlparser::ast::{Value, ValueWithSpan};
/// # use sqlparser::tokenizer::{Location, Span};
/// let value = Value::SingleQuotedString(String::from("endpoint"));
/// // converting `Value` to `ValueWithSpan` results in an empty span
/// let value_with_span: ValueWithSpan = value.into();
/// assert_eq!(value_with_span.span, Span::empty());
/// // convert back to `Value`
/// let value: Value = value_with_span.into();
/// ```
#[derive(Debug, Clone, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct ValueWithSpan {
pub value: Value,
pub span: Span,
}
impl PartialEq for ValueWithSpan {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl Ord for ValueWithSpan {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.value.cmp(&other.value)
}
}
impl PartialOrd for ValueWithSpan {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(Ord::cmp(self, other))
}
}
impl core::hash::Hash for ValueWithSpan {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl From<Value> for ValueWithSpan {
fn from(value: Value) -> Self {
value.with_empty_span()
}
}
impl From<ValueWithSpan> for Value {
fn from(value: ValueWithSpan) -> Self {
value.value
}
}
/// Primitive SQL values such as number and string
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "visitor",
derive(Visit, VisitMut),
visit(with = "visit_value")
)]
pub enum Value {
/// Numeric literal
#[cfg(not(feature = "bigdecimal"))]
Number(String, bool),
#[cfg(feature = "bigdecimal")]
// HINT: use `test_utils::number` to make an instance of
// Value::Number This might help if you your tests pass locally
// but fail on CI with the `--all-features` flag enabled
Number(BigDecimal, bool),
/// 'string value'
SingleQuotedString(String),
// $<tag_name>$string value$<tag_name>$ (postgres syntax)
DollarQuotedString(DollarQuotedString),
/// Triple single quoted strings: Example '''abc'''
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleSingleQuotedString(String),
/// Triple double quoted strings: Example """abc"""
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleDoubleQuotedString(String),
/// e'string value' (postgres extension)
/// See [Postgres docs](https://www.postgresql.org/docs/8.3/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS)
/// for more details.
EscapedStringLiteral(String),
/// u&'string value' (postgres extension)
/// See [Postgres docs](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-UESCAPE)
/// for more details.
UnicodeStringLiteral(String),
/// B'string value'
SingleQuotedByteStringLiteral(String),
/// B"string value"
DoubleQuotedByteStringLiteral(String),
/// Triple single quoted literal with byte string prefix. Example `B'''abc'''`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleSingleQuotedByteStringLiteral(String),
/// Triple double quoted literal with byte string prefix. Example `B"""abc"""`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleDoubleQuotedByteStringLiteral(String),
/// Single quoted literal with raw string prefix. Example `R'abc'`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
SingleQuotedRawStringLiteral(String),
/// Double quoted literal with raw string prefix. Example `R"abc"`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
DoubleQuotedRawStringLiteral(String),
/// Triple single quoted literal with raw string prefix. Example `R'''abc'''`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleSingleQuotedRawStringLiteral(String),
/// Triple double quoted literal with raw string prefix. Example `R"""abc"""`
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
TripleDoubleQuotedRawStringLiteral(String),
/// N'string value'
NationalStringLiteral(String),
/// X'hex value'
HexStringLiteral(String),
DoubleQuotedString(String),
/// Boolean value true or false
Boolean(bool),
/// `NULL` value
Null,
/// `?` or `$` Prepared statement arg placeholder
Placeholder(String),
}
impl ValueWithSpan {
/// If the underlying literal is a string, regardless of quote style, returns the associated string value
pub fn into_string(self) -> Option<String> {
self.value.into_string()
}
}
impl Value {
/// If the underlying literal is a string, regardless of quote style, returns the associated string value
pub fn into_string(self) -> Option<String> {
match self {
Value::SingleQuotedString(s)
| Value::DoubleQuotedString(s)
| Value::TripleSingleQuotedString(s)
| Value::TripleDoubleQuotedString(s)
| Value::SingleQuotedByteStringLiteral(s)
| Value::DoubleQuotedByteStringLiteral(s)
| Value::TripleSingleQuotedByteStringLiteral(s)
| Value::TripleDoubleQuotedByteStringLiteral(s)
| Value::SingleQuotedRawStringLiteral(s)
| Value::DoubleQuotedRawStringLiteral(s)
| Value::TripleSingleQuotedRawStringLiteral(s)
| Value::TripleDoubleQuotedRawStringLiteral(s)
| Value::EscapedStringLiteral(s)
| Value::UnicodeStringLiteral(s)
| Value::NationalStringLiteral(s)
| Value::HexStringLiteral(s) => Some(s),
Value::DollarQuotedString(s) => Some(s.value),
_ => None,
}
}
pub fn with_span(self, span: Span) -> ValueWithSpan {
ValueWithSpan { value: self, span }
}
pub fn with_empty_span(self) -> ValueWithSpan {
self.with_span(Span::empty())
}
}
impl fmt::Display for ValueWithSpan {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Value::Number(v, l) => write!(f, "{}{long}", v, long = if *l { "L" } else { "" }),
Value::DoubleQuotedString(v) => write!(f, "\"{}\"", escape_double_quote_string(v)),
Value::SingleQuotedString(v) => write!(f, "'{}'", escape_single_quote_string(v)),
Value::TripleSingleQuotedString(v) => {
write!(f, "'''{v}'''")
}
Value::TripleDoubleQuotedString(v) => {
write!(f, r#""""{v}""""#)
}
Value::DollarQuotedString(v) => write!(f, "{v}"),
Value::EscapedStringLiteral(v) => write!(f, "E'{}'", escape_escaped_string(v)),
Value::UnicodeStringLiteral(v) => write!(f, "U&'{}'", escape_unicode_string(v)),
Value::NationalStringLiteral(v) => write!(f, "N'{v}'"),
Value::HexStringLiteral(v) => write!(f, "X'{v}'"),
Value::Boolean(v) => write!(f, "{v}"),
Value::SingleQuotedByteStringLiteral(v) => write!(f, "B'{v}'"),
Value::DoubleQuotedByteStringLiteral(v) => write!(f, "B\"{v}\""),
Value::TripleSingleQuotedByteStringLiteral(v) => write!(f, "B'''{v}'''"),
Value::TripleDoubleQuotedByteStringLiteral(v) => write!(f, r#"B"""{v}""""#),
Value::SingleQuotedRawStringLiteral(v) => write!(f, "R'{v}'"),
Value::DoubleQuotedRawStringLiteral(v) => write!(f, "R\"{v}\""),
Value::TripleSingleQuotedRawStringLiteral(v) => write!(f, "R'''{v}'''"),
Value::TripleDoubleQuotedRawStringLiteral(v) => write!(f, r#"R"""{v}""""#),
Value::Null => write!(f, "NULL"),
Value::Placeholder(v) => write!(f, "{v}"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct DollarQuotedString {
pub value: String,
pub tag: Option<String>,
}
impl fmt::Display for DollarQuotedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.tag {
Some(tag) => {
write!(f, "${}${}${}$", tag, self.value, tag)
}
None => {
write!(f, "$${}$$", self.value)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum DateTimeField {
Year,
Years,
Month,
Months,
/// Week optionally followed by a WEEKDAY.
///
/// ```sql
/// WEEK(MONDAY)
/// ```
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions#extract)
Week(Option<Ident>),
Weeks,
Day,
DayOfWeek,
DayOfYear,
Days,
Date,
Datetime,
Hour,
Hours,
Minute,
Minutes,
Second,
Seconds,
Century,
Decade,
Dow,
Doy,
Epoch,
Isodow,
IsoWeek,
Isoyear,
Julian,
Microsecond,
Microseconds,
Millenium,
Millennium,
Millisecond,
Milliseconds,
Nanosecond,
Nanoseconds,
Quarter,
Time,
Timezone,
TimezoneAbbr,
TimezoneHour,
TimezoneMinute,
TimezoneRegion,
NoDateTime,
/// Arbitrary abbreviation or custom date-time part.
///
/// ```sql
/// EXTRACT(q FROM CURRENT_TIMESTAMP)
/// ```
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/functions-date-time#supported-date-and-time-parts)
Custom(Ident),
}
impl fmt::Display for DateTimeField {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DateTimeField::Year => write!(f, "YEAR"),
DateTimeField::Years => write!(f, "YEARS"),
DateTimeField::Month => write!(f, "MONTH"),
DateTimeField::Months => write!(f, "MONTHS"),
DateTimeField::Week(week_day) => {
write!(f, "WEEK")?;
if let Some(week_day) = week_day {
write!(f, "({week_day})")?
}
Ok(())
}
DateTimeField::Weeks => write!(f, "WEEKS"),
DateTimeField::Day => write!(f, "DAY"),
DateTimeField::DayOfWeek => write!(f, "DAYOFWEEK"),
DateTimeField::DayOfYear => write!(f, "DAYOFYEAR"),
DateTimeField::Days => write!(f, "DAYS"),
DateTimeField::Date => write!(f, "DATE"),
DateTimeField::Datetime => write!(f, "DATETIME"),
DateTimeField::Hour => write!(f, "HOUR"),
DateTimeField::Hours => write!(f, "HOURS"),
DateTimeField::Minute => write!(f, "MINUTE"),
DateTimeField::Minutes => write!(f, "MINUTES"),
DateTimeField::Second => write!(f, "SECOND"),
DateTimeField::Seconds => write!(f, "SECONDS"),
DateTimeField::Century => write!(f, "CENTURY"),
DateTimeField::Decade => write!(f, "DECADE"),
DateTimeField::Dow => write!(f, "DOW"),
DateTimeField::Doy => write!(f, "DOY"),
DateTimeField::Epoch => write!(f, "EPOCH"),
DateTimeField::Isodow => write!(f, "ISODOW"),
DateTimeField::Isoyear => write!(f, "ISOYEAR"),
DateTimeField::IsoWeek => write!(f, "ISOWEEK"),
DateTimeField::Julian => write!(f, "JULIAN"),
DateTimeField::Microsecond => write!(f, "MICROSECOND"),
DateTimeField::Microseconds => write!(f, "MICROSECONDS"),
DateTimeField::Millenium => write!(f, "MILLENIUM"),
DateTimeField::Millennium => write!(f, "MILLENNIUM"),
DateTimeField::Millisecond => write!(f, "MILLISECOND"),
DateTimeField::Milliseconds => write!(f, "MILLISECONDS"),
DateTimeField::Nanosecond => write!(f, "NANOSECOND"),
DateTimeField::Nanoseconds => write!(f, "NANOSECONDS"),
DateTimeField::Quarter => write!(f, "QUARTER"),
DateTimeField::Time => write!(f, "TIME"),
DateTimeField::Timezone => write!(f, "TIMEZONE"),
DateTimeField::TimezoneAbbr => write!(f, "TIMEZONE_ABBR"),
DateTimeField::TimezoneHour => write!(f, "TIMEZONE_HOUR"),
DateTimeField::TimezoneMinute => write!(f, "TIMEZONE_MINUTE"),
DateTimeField::TimezoneRegion => write!(f, "TIMEZONE_REGION"),
DateTimeField::NoDateTime => write!(f, "NODATETIME"),
DateTimeField::Custom(custom) => write!(f, "{custom}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
/// The Unicode Standard defines four normalization forms, which are intended to eliminate
/// certain distinctions between visually or functionally identical characters.
///
/// See [Unicode Normalization Forms](https://unicode.org/reports/tr15/) for details.
pub enum NormalizationForm {
/// Canonical Decomposition, followed by Canonical Composition.
NFC,
/// Canonical Decomposition.
NFD,
/// Compatibility Decomposition, followed by Canonical Composition.
NFKC,
/// Compatibility Decomposition.
NFKD,
}
impl fmt::Display for NormalizationForm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
NormalizationForm::NFC => write!(f, "NFC"),
NormalizationForm::NFD => write!(f, "NFD"),
NormalizationForm::NFKC => write!(f, "NFKC"),
NormalizationForm::NFKD => write!(f, "NFKD"),
}
}
}
pub struct EscapeQuotedString<'a> {
string: &'a str,
quote: char,
}
impl fmt::Display for EscapeQuotedString<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// EscapeQuotedString doesn't know which mode of escape was
// chosen by the user. So this code must to correctly display
// strings without knowing if the strings are already escaped
// or not.
//
// If the quote symbol in the string is repeated twice, OR, if
// the quote symbol is after backslash, display all the chars
// without any escape. However, if the quote symbol is used
// just between usual chars, `fmt()` should display it twice."
//
// The following table has examples
//
// | original query | mode | AST Node | serialized |
// | ------------- | --------- | -------------------------------------------------- | ------------ |
// | `"A""B""A"` | no-escape | `DoubleQuotedString(String::from("A\"\"B\"\"A"))` | `"A""B""A"` |
// | `"A""B""A"` | default | `DoubleQuotedString(String::from("A\"B\"A"))` | `"A""B""A"` |
// | `"A\"B\"A"` | no-escape | `DoubleQuotedString(String::from("A\\\"B\\\"A"))` | `"A\"B\"A"` |
// | `"A\"B\"A"` | default | `DoubleQuotedString(String::from("A\"B\"A"))` | `"A""B""A"` |
let quote = self.quote;
let mut previous_char = char::default();
let mut start_idx = 0;
let mut peekable_chars = self.string.char_indices().peekable();
while let Some(&(idx, ch)) = peekable_chars.peek() {
match ch {
char if char == quote => {
if previous_char == '\\' {
// the quote is already escaped with a backslash, skip
peekable_chars.next();
continue;
}
peekable_chars.next();
match peekable_chars.peek() {
Some((_, c)) if *c == quote => {
// the quote is already escaped with another quote, skip
peekable_chars.next();
}
_ => {
// The quote is not escaped.
// Including idx in the range, so the quote at idx will be printed twice:
// in this call to write_str() and in the next one.
f.write_str(&self.string[start_idx..=idx])?;
start_idx = idx;
}
}
}
_ => {
peekable_chars.next();
}
}
previous_char = ch;
}
f.write_str(&self.string[start_idx..])?;
Ok(())
}
}
pub fn escape_quoted_string(string: &str, quote: char) -> EscapeQuotedString<'_> {
EscapeQuotedString { string, quote }
}
pub fn escape_single_quote_string(s: &str) -> EscapeQuotedString<'_> {
escape_quoted_string(s, '\'')
}
pub fn escape_double_quote_string(s: &str) -> EscapeQuotedString<'_> {
escape_quoted_string(s, '\"')
}
pub struct EscapeEscapedStringLiteral<'a>(&'a str);
impl fmt::Display for EscapeEscapedStringLiteral<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.0.chars() {
match c {
'\'' => {
write!(f, r#"\'"#)?;
}
'\\' => {
write!(f, r#"\\"#)?;
}
'\n' => {
write!(f, r#"\n"#)?;
}
'\t' => {
write!(f, r#"\t"#)?;
}
'\r' => {
write!(f, r#"\r"#)?;
}
_ => {
write!(f, "{c}")?;
}
}
}
Ok(())
}
}
pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> {
EscapeEscapedStringLiteral(s)
}
pub struct EscapeUnicodeStringLiteral<'a>(&'a str);
impl fmt::Display for EscapeUnicodeStringLiteral<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.0.chars() {
match c {
'\'' => {
write!(f, "''")?;
}
'\\' => {
write!(f, r#"\\"#)?;
}
x if x.is_ascii() => {
write!(f, "{c}")?;
}
_ => {
let codepoint = c as u32;
// if the character fits in 32 bits, we can use the \XXXX format
// otherwise, we need to use the \+XXXXXX format
if codepoint <= 0xFFFF {
write!(f, "\\{codepoint:04X}")?;
} else {
write!(f, "\\+{codepoint:06X}")?;
}
}
}
}
Ok(())
}
}
pub fn escape_unicode_string(s: &str) -> EscapeUnicodeStringLiteral<'_> {
EscapeUnicodeStringLiteral(s)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum TrimWhereField {
Both,
Leading,
Trailing,
}
impl fmt::Display for TrimWhereField {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TrimWhereField::*;
f.write_str(match self {
Both => "BOTH",
Leading => "LEADING",
Trailing => "TRAILING",
})
}
}

1010
src/ast/visitor.rs Normal file

File diff suppressed because it is too large Load diff

36
src/dialect/ansi.rs Normal file
View file

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
/// A [`Dialect`] for [ANSI SQL](https://en.wikipedia.org/wiki/SQL:2011).
#[derive(Debug)]
pub struct AnsiDialect {}
impl Dialect for AnsiDialect {
fn is_identifier_start(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase()
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
}
fn require_interval_qualifier(&self) -> bool {
true
}
}

147
src/dialect/bigquery.rs Normal file
View file

@ -0,0 +1,147 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::ast::Statement;
use crate::dialect::Dialect;
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
/// These keywords are disallowed as column identifiers. Such that
/// `SELECT 5 AS <col> FROM T` is rejected by BigQuery.
const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[
Keyword::WITH,
Keyword::SELECT,
Keyword::WHERE,
Keyword::GROUP,
Keyword::HAVING,
Keyword::ORDER,
Keyword::LATERAL,
Keyword::LIMIT,
Keyword::FETCH,
Keyword::UNION,
Keyword::EXCEPT,
Keyword::INTERSECT,
Keyword::FROM,
Keyword::INTO,
Keyword::END,
];
/// A [`Dialect`] for [Google Bigquery](https://cloud.google.com/bigquery/)
#[derive(Debug, Default)]
pub struct BigQueryDialect;
impl Dialect for BigQueryDialect {
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::BEGIN) {
return Some(parser.parse_begin_exception_end());
}
None
}
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#identifiers>
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`'
}
fn supports_projection_trailing_commas(&self) -> bool {
true
}
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_table_statement>
fn supports_column_definition_trailing_commas(&self) -> bool {
true
}
fn is_identifier_start(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
// BigQuery supports `@@foo.bar` variable syntax in its procedural language.
// https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#beginexceptionend
|| ch == '@'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_'
}
/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#quoted_literals)
fn supports_triple_quoted_string(&self) -> bool {
true
}
/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions#first_value)
fn supports_window_function_null_treatment_arg(&self) -> bool {
true
}
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#escape_sequences
fn supports_string_literal_backslash_escape(&self) -> bool {
true
}
/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/window-function-calls#ref_named_window)
fn supports_window_clause_named_window_reference(&self) -> bool {
true
}
/// See [doc](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#set)
fn supports_parenthesized_set_variables(&self) -> bool {
true
}
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_except
fn supports_select_wildcard_except(&self) -> bool {
true
}
fn require_interval_qualifier(&self) -> bool {
true
}
// See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#constructing_a_struct
fn supports_struct_literal(&self) -> bool {
true
}
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select_expression_star>
fn supports_select_expr_star(&self) -> bool {
true
}
/// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#execute_immediate>
fn supports_execute_immediate(&self) -> bool {
true
}
// See <https://cloud.google.com/bigquery/docs/access-historical-data>
fn supports_timestamp_versioning(&self) -> bool {
true
}
// See <https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#group_by_clause>
fn supports_group_by_expr(&self) -> bool {
true
}
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
!RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}
fn supports_pipe_operator(&self) -> bool {
true
}
}

97
src/dialect/clickhouse.rs Normal file
View file

@ -0,0 +1,97 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
// A [`Dialect`] for [ClickHouse](https://clickhouse.com/).
#[derive(Debug)]
pub struct ClickHouseDialect {}
impl Dialect for ClickHouseDialect {
fn is_identifier_start(&self, ch: char) -> bool {
// See https://clickhouse.com/docs/en/sql-reference/syntax/#syntax-identifiers
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
}
fn is_identifier_part(&self, ch: char) -> bool {
self.is_identifier_start(ch) || ch.is_ascii_digit()
}
fn supports_string_literal_backslash_escape(&self) -> bool {
true
}
fn supports_select_wildcard_except(&self) -> bool {
true
}
fn describe_requires_table_keyword(&self) -> bool {
true
}
fn require_interval_qualifier(&self) -> bool {
true
}
fn supports_limit_comma(&self) -> bool {
true
}
fn supports_insert_table_function(&self) -> bool {
true
}
fn supports_insert_format(&self) -> bool {
true
}
fn supports_numeric_literal_underscores(&self) -> bool {
true
}
// ClickHouse uses this for some FORMAT expressions in `INSERT` context, e.g. when inserting
// with FORMAT JSONEachRow a raw JSON key-value expression is valid and expected.
//
// [ClickHouse formats](https://clickhouse.com/docs/en/interfaces/formats)
fn supports_dictionary_syntax(&self) -> bool {
true
}
/// See <https://clickhouse.com/docs/en/sql-reference/functions#higher-order-functions---operator-and-lambdaparams-expr-function>
fn supports_lambda_functions(&self) -> bool {
true
}
fn supports_from_first_select(&self) -> bool {
true
}
/// See <https://clickhouse.com/docs/en/sql-reference/statements/select/order-by>
fn supports_order_by_all(&self) -> bool {
true
}
// See <https://clickhouse.com/docs/en/sql-reference/aggregate-functions/grouping_function#grouping-sets>
fn supports_group_by_expr(&self) -> bool {
true
}
/// See <https://clickhouse.com/docs/en/sql-reference/statements/select/group-by#rollup-modifier>
fn supports_group_by_with_modifier(&self) -> bool {
true
}
}

67
src/dialect/databricks.rs Normal file
View file

@ -0,0 +1,67 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
/// A [`Dialect`] for [Databricks SQL](https://www.databricks.com/)
///
/// See <https://docs.databricks.com/en/sql/language-manual/index.html>.
#[derive(Debug, Default)]
pub struct DatabricksDialect;
impl Dialect for DatabricksDialect {
// see https://docs.databricks.com/en/sql/language-manual/sql-ref-identifiers.html
fn is_delimited_identifier_start(&self, ch: char) -> bool {
matches!(ch, '`')
}
fn is_identifier_start(&self, ch: char) -> bool {
matches!(ch, 'a'..='z' | 'A'..='Z' | '_')
}
fn is_identifier_part(&self, ch: char) -> bool {
matches!(ch, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-groupby.html
fn supports_group_by_expr(&self) -> bool {
true
}
fn supports_lambda_functions(&self) -> bool {
true
}
// https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select.html#syntax
fn supports_select_wildcard_except(&self) -> bool {
true
}
fn require_interval_qualifier(&self) -> bool {
true
}
// See https://docs.databricks.com/en/sql/language-manual/functions/struct.html
fn supports_struct_literal(&self) -> bool {
true
}
}

97
src/dialect/duckdb.rs Normal file
View file

@ -0,0 +1,97 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
/// A [`Dialect`] for [DuckDB](https://duckdb.org/)
#[derive(Debug, Default)]
pub struct DuckDbDialect;
// In most cases the redshift dialect is identical to [`PostgresSqlDialect`].
impl Dialect for DuckDbDialect {
fn supports_trailing_commas(&self) -> bool {
true
}
fn is_identifier_start(&self, ch: char) -> bool {
ch.is_alphabetic() || ch == '_'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
fn supports_group_by_expr(&self) -> bool {
true
}
fn supports_named_fn_args_with_eq_operator(&self) -> bool {
true
}
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
true
}
// DuckDB uses this syntax for `STRUCT`s.
//
// https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
fn supports_dictionary_syntax(&self) -> bool {
true
}
// DuckDB uses this syntax for `MAP`s.
//
// https://duckdb.org/docs/sql/data_types/map.html#creating-maps
fn support_map_literal_syntax(&self) -> bool {
true
}
/// See <https://duckdb.org/docs/sql/functions/lambda.html>
fn supports_lambda_functions(&self) -> bool {
true
}
// DuckDB is compatible with PostgreSQL syntax for this statement,
// although not all features may be implemented.
fn supports_explain_with_utility_options(&self) -> bool {
true
}
/// See DuckDB <https://duckdb.org/docs/sql/statements/load_and_install.html#load>
fn supports_load_extension(&self) -> bool {
true
}
// See DuckDB <https://duckdb.org/docs/sql/data_types/array.html#defining-an-array-field>
fn supports_array_typedef_with_brackets(&self) -> bool {
true
}
fn supports_from_first_select(&self) -> bool {
true
}
/// See DuckDB <https://duckdb.org/docs/sql/query_syntax/orderby.html#order-by-all-examples>
fn supports_order_by_all(&self) -> bool {
true
}
}

182
src/dialect/generic.rs Normal file
View file

@ -0,0 +1,182 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
/// A permissive, general purpose [`Dialect`], which parses a wide variety of SQL
/// statements, from many different dialects.
#[derive(Debug, Default)]
pub struct GenericDialect;
impl Dialect for GenericDialect {
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '`'
}
fn is_identifier_start(&self, ch: char) -> bool {
ch.is_alphabetic() || ch == '_' || ch == '#' || ch == '@'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_alphabetic()
|| ch.is_ascii_digit()
|| ch == '@'
|| ch == '$'
|| ch == '#'
|| ch == '_'
}
fn supports_unicode_string_literal(&self) -> bool {
true
}
fn supports_group_by_expr(&self) -> bool {
true
}
fn supports_group_by_with_modifier(&self) -> bool {
true
}
fn supports_left_associative_joins_without_parens(&self) -> bool {
true
}
fn supports_connect_by(&self) -> bool {
true
}
fn supports_match_recognize(&self) -> bool {
true
}
fn supports_start_transaction_modifier(&self) -> bool {
true
}
fn supports_window_function_null_treatment_arg(&self) -> bool {
true
}
fn supports_dictionary_syntax(&self) -> bool {
true
}
fn supports_window_clause_named_window_reference(&self) -> bool {
true
}
fn supports_parenthesized_set_variables(&self) -> bool {
true
}
fn supports_select_wildcard_except(&self) -> bool {
true
}
fn support_map_literal_syntax(&self) -> bool {
true
}
fn allow_extract_custom(&self) -> bool {
true
}
fn allow_extract_single_quotes(&self) -> bool {
true
}
fn supports_create_index_with_clause(&self) -> bool {
true
}
fn supports_explain_with_utility_options(&self) -> bool {
true
}
fn supports_limit_comma(&self) -> bool {
true
}
fn supports_from_first_select(&self) -> bool {
true
}
fn supports_projection_trailing_commas(&self) -> bool {
true
}
fn supports_asc_desc_in_column_definition(&self) -> bool {
true
}
fn supports_try_convert(&self) -> bool {
true
}
fn supports_comment_on(&self) -> bool {
true
}
fn supports_load_extension(&self) -> bool {
true
}
fn supports_named_fn_args_with_assignment_operator(&self) -> bool {
true
}
fn supports_struct_literal(&self) -> bool {
true
}
fn supports_empty_projections(&self) -> bool {
true
}
fn supports_nested_comments(&self) -> bool {
true
}
fn supports_user_host_grantee(&self) -> bool {
true
}
fn supports_string_escape_constant(&self) -> bool {
true
}
fn supports_array_typedef_with_brackets(&self) -> bool {
true
}
fn supports_match_against(&self) -> bool {
true
}
fn supports_set_names(&self) -> bool {
true
}
fn supports_comma_separated_set_assignments(&self) -> bool {
true
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
}

74
src/dialect/hive.rs Normal file
View file

@ -0,0 +1,74 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
/// A [`Dialect`] for [Hive](https://hive.apache.org/).
#[derive(Debug)]
pub struct HiveDialect {}
impl Dialect for HiveDialect {
fn is_delimited_identifier_start(&self, ch: char) -> bool {
(ch == '"') || (ch == '`')
}
fn is_identifier_start(&self, ch: char) -> bool {
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '$'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase()
|| ch.is_ascii_uppercase()
|| ch.is_ascii_digit()
|| ch == '_'
|| ch == '$'
|| ch == '{'
|| ch == '}'
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
fn supports_numeric_prefix(&self) -> bool {
true
}
fn require_interval_qualifier(&self) -> bool {
true
}
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362061#Tutorial-BuiltInOperators>
fn supports_bang_not_operator(&self) -> bool {
true
}
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362036#LanguageManualDML-Loadingfilesintotables>
fn supports_load_data(&self) -> bool {
true
}
/// See <https://cwiki.apache.org/confluence/display/hive/languagemanual+sampling>
fn supports_table_sample_before_alias(&self) -> bool {
true
}
/// See <https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=30151323#EnhancedAggregation,Cube,GroupingandRollup-CubesandRollupsr>
fn supports_group_by_with_modifier(&self) -> bool {
true
}
}

1312
src/dialect/mod.rs Normal file

File diff suppressed because it is too large Load diff

298
src/dialect/mssql.rs Normal file
View file

@ -0,0 +1,298 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::ast::helpers::attached_token::AttachedToken;
use crate::ast::{
BeginEndStatements, ConditionalStatementBlock, ConditionalStatements, GranteesType,
IfStatement, Statement, TriggerObject,
};
use crate::dialect::Dialect;
use crate::keywords::{self, Keyword};
use crate::parser::{Parser, ParserError};
use crate::tokenizer::Token;
#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};
const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[Keyword::IF, Keyword::ELSE];
/// A [`Dialect`] for [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server/)
#[derive(Debug)]
pub struct MsSqlDialect {}
impl Dialect for MsSqlDialect {
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' || ch == '['
}
fn is_identifier_start(&self, ch: char) -> bool {
// See https://docs.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-2017#rules-for-regular-identifiers
ch.is_alphabetic() || ch == '_' || ch == '#' || ch == '@'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_alphabetic()
|| ch.is_ascii_digit()
|| ch == '@'
|| ch == '$'
|| ch == '#'
|| ch == '_'
}
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
Some('[')
}
/// SQL Server has `CONVERT(type, value)` instead of `CONVERT(value, type)`
/// <https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16>
fn convert_type_before_value(&self) -> bool {
true
}
fn supports_outer_join_operator(&self) -> bool {
true
}
fn supports_connect_by(&self) -> bool {
true
}
fn supports_eq_alias_assignment(&self) -> bool {
true
}
fn supports_try_convert(&self) -> bool {
true
}
/// In MSSQL, there is no boolean type, and `true` and `false` are valid column names
fn supports_boolean_literals(&self) -> bool {
false
}
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
true
}
fn supports_named_fn_args_with_expr_name(&self) -> bool {
true
}
fn supports_named_fn_args_with_rarrow_operator(&self) -> bool {
false
}
fn supports_start_transaction_modifier(&self) -> bool {
true
}
fn supports_end_transaction_modifier(&self) -> bool {
true
}
/// See: <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
fn supports_set_stmt_without_operator(&self) -> bool {
true
}
/// See: <https://learn.microsoft.com/en-us/sql/relational-databases/tables/querying-data-in-a-system-versioned-temporal-table>
fn supports_timestamp_versioning(&self) -> bool {
true
}
/// See <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/slash-star-comment-transact-sql?view=sql-server-ver16>
fn supports_nested_comments(&self) -> bool {
true
}
/// See <https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql>
fn supports_object_name_double_dot_notation(&self) -> bool {
true
}
/// See <https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/server-level-roles>
fn get_reserved_grantees_types(&self) -> &[GranteesType] {
&[GranteesType::Public]
}
fn is_column_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.peek_keyword(Keyword::IF) {
Some(self.parse_if_stmt(parser))
} else if parser.parse_keywords(&[Keyword::CREATE, Keyword::TRIGGER]) {
Some(self.parse_create_trigger(parser, false))
} else if parser.parse_keywords(&[
Keyword::CREATE,
Keyword::OR,
Keyword::ALTER,
Keyword::TRIGGER,
]) {
Some(self.parse_create_trigger(parser, true))
} else {
None
}
}
}
impl MsSqlDialect {
/// ```sql
/// IF boolean_expression
/// { sql_statement | statement_block }
/// [ ELSE
/// { sql_statement | statement_block } ]
/// ```
fn parse_if_stmt(&self, parser: &mut Parser) -> Result<Statement, ParserError> {
let if_token = parser.expect_keyword(Keyword::IF)?;
let condition = parser.parse_expr()?;
let if_block = if parser.peek_keyword(Keyword::BEGIN) {
let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
let end_token = parser.expect_keyword(Keyword::END)?;
ConditionalStatementBlock {
start_token: AttachedToken(if_token),
condition: Some(condition),
then_token: None,
conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
begin_token: AttachedToken(begin_token),
statements,
end_token: AttachedToken(end_token),
}),
}
} else {
let stmt = parser.parse_statement()?;
ConditionalStatementBlock {
start_token: AttachedToken(if_token),
condition: Some(condition),
then_token: None,
conditional_statements: ConditionalStatements::Sequence {
statements: vec![stmt],
},
}
};
let mut prior_statement_ended_with_semi_colon = false;
while let Token::SemiColon = parser.peek_token_ref().token {
parser.advance_token();
prior_statement_ended_with_semi_colon = true;
}
let mut else_block = None;
if parser.peek_keyword(Keyword::ELSE) {
let else_token = parser.expect_keyword(Keyword::ELSE)?;
if parser.peek_keyword(Keyword::BEGIN) {
let begin_token = parser.expect_keyword(Keyword::BEGIN)?;
let statements = self.parse_statement_list(parser, Some(Keyword::END))?;
let end_token = parser.expect_keyword(Keyword::END)?;
else_block = Some(ConditionalStatementBlock {
start_token: AttachedToken(else_token),
condition: None,
then_token: None,
conditional_statements: ConditionalStatements::BeginEnd(BeginEndStatements {
begin_token: AttachedToken(begin_token),
statements,
end_token: AttachedToken(end_token),
}),
});
} else {
let stmt = parser.parse_statement()?;
else_block = Some(ConditionalStatementBlock {
start_token: AttachedToken(else_token),
condition: None,
then_token: None,
conditional_statements: ConditionalStatements::Sequence {
statements: vec![stmt],
},
});
}
} else if prior_statement_ended_with_semi_colon {
parser.prev_token();
}
Ok(Statement::If(IfStatement {
if_block,
else_block,
elseif_blocks: Vec::new(),
end_token: None,
}))
}
/// Parse `CREATE TRIGGER` for [MsSql]
///
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
fn parse_create_trigger(
&self,
parser: &mut Parser,
or_alter: bool,
) -> Result<Statement, ParserError> {
let name = parser.parse_object_name(false)?;
parser.expect_keyword_is(Keyword::ON)?;
let table_name = parser.parse_object_name(false)?;
let period = parser.parse_trigger_period()?;
let events = parser.parse_comma_separated(Parser::parse_trigger_event)?;
parser.expect_keyword_is(Keyword::AS)?;
let statements = Some(parser.parse_conditional_statements(&[Keyword::END])?);
Ok(Statement::CreateTrigger {
or_alter,
or_replace: false,
is_constraint: false,
name,
period,
events,
table_name,
referenced_table_name: None,
referencing: Vec::new(),
trigger_object: TriggerObject::Statement,
include_each: false,
condition: None,
exec_body: None,
statements,
characteristics: None,
})
}
/// Parse a sequence of statements, optionally separated by semicolon.
///
/// Stops parsing when reaching EOF or the given keyword.
fn parse_statement_list(
&self,
parser: &mut Parser,
terminal_keyword: Option<Keyword>,
) -> Result<Vec<Statement>, ParserError> {
let mut stmts = Vec::new();
loop {
if let Token::EOF = parser.peek_token_ref().token {
break;
}
if let Some(term) = terminal_keyword {
if parser.peek_keyword(term) {
break;
}
}
stmts.push(parser.parse_statement()?);
while let Token::SemiColon = parser.peek_token_ref().token {
parser.advance_token();
}
}
Ok(stmts)
}
}

199
src/dialect/mysql.rs Normal file
View file

@ -0,0 +1,199 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
use crate::{
ast::{BinaryOperator, Expr, LockTable, LockTableType, Statement},
dialect::Dialect,
keywords::Keyword,
parser::{Parser, ParserError},
};
use super::keywords;
const RESERVED_FOR_TABLE_ALIAS_MYSQL: &[Keyword] = &[
Keyword::USE,
Keyword::IGNORE,
Keyword::FORCE,
Keyword::STRAIGHT_JOIN,
];
/// A [`Dialect`] for [MySQL](https://www.mysql.com/)
#[derive(Debug)]
pub struct MySqlDialect {}
impl Dialect for MySqlDialect {
fn is_identifier_start(&self, ch: char) -> bool {
// See https://dev.mysql.com/doc/refman/8.0/en/identifiers.html.
// Identifiers which begin with a digit are recognized while tokenizing numbers,
// so they can be distinguished from exponent numeric literals.
ch.is_alphabetic()
|| ch == '_'
|| ch == '$'
|| ch == '@'
|| ('\u{0080}'..='\u{ffff}').contains(&ch)
}
fn is_identifier_part(&self, ch: char) -> bool {
self.is_identifier_start(ch) || ch.is_ascii_digit()
}
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`'
}
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
Some('`')
}
// See https://dev.mysql.com/doc/refman/8.0/en/string-literals.html#character-escape-sequences
fn supports_string_literal_backslash_escape(&self) -> bool {
true
}
fn ignores_wildcard_escapes(&self) -> bool {
true
}
fn supports_numeric_prefix(&self) -> bool {
true
}
fn parse_infix(
&self,
parser: &mut crate::parser::Parser,
expr: &crate::ast::Expr,
_precedence: u8,
) -> Option<Result<crate::ast::Expr, ParserError>> {
// Parse DIV as an operator
if parser.parse_keyword(Keyword::DIV) {
Some(Ok(Expr::BinaryOp {
left: Box::new(expr.clone()),
op: BinaryOperator::MyIntegerDivide,
right: Box::new(parser.parse_expr().unwrap()),
}))
} else {
None
}
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keywords(&[Keyword::LOCK, Keyword::TABLES]) {
Some(parse_lock_tables(parser))
} else if parser.parse_keywords(&[Keyword::UNLOCK, Keyword::TABLES]) {
Some(parse_unlock_tables(parser))
} else {
None
}
}
fn require_interval_qualifier(&self) -> bool {
true
}
fn supports_limit_comma(&self) -> bool {
true
}
/// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table-select.html>
fn supports_create_table_select(&self) -> bool {
true
}
/// See: <https://dev.mysql.com/doc/refman/8.4/en/insert.html>
fn supports_insert_set(&self) -> bool {
true
}
fn supports_user_host_grantee(&self) -> bool {
true
}
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, _parser: &mut Parser) -> bool {
explicit
|| (!keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
&& !RESERVED_FOR_TABLE_ALIAS_MYSQL.contains(kw))
}
fn supports_table_hints(&self) -> bool {
true
}
fn requires_single_line_comment_whitespace(&self) -> bool {
true
}
fn supports_match_against(&self) -> bool {
true
}
fn supports_set_names(&self) -> bool {
true
}
fn supports_comma_separated_set_assignments(&self) -> bool {
true
}
}
/// `LOCK TABLES`
/// <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
fn parse_lock_tables(parser: &mut Parser) -> Result<Statement, ParserError> {
let tables = parser.parse_comma_separated(parse_lock_table)?;
Ok(Statement::LockTables { tables })
}
// tbl_name [[AS] alias] lock_type
fn parse_lock_table(parser: &mut Parser) -> Result<LockTable, ParserError> {
let table = parser.parse_identifier()?;
let alias =
parser.parse_optional_alias(&[Keyword::READ, Keyword::WRITE, Keyword::LOW_PRIORITY])?;
let lock_type = parse_lock_tables_type(parser)?;
Ok(LockTable {
table,
alias,
lock_type,
})
}
// READ [LOCAL] | [LOW_PRIORITY] WRITE
fn parse_lock_tables_type(parser: &mut Parser) -> Result<LockTableType, ParserError> {
if parser.parse_keyword(Keyword::READ) {
if parser.parse_keyword(Keyword::LOCAL) {
Ok(LockTableType::Read { local: true })
} else {
Ok(LockTableType::Read { local: false })
}
} else if parser.parse_keyword(Keyword::WRITE) {
Ok(LockTableType::Write {
low_priority: false,
})
} else if parser.parse_keywords(&[Keyword::LOW_PRIORITY, Keyword::WRITE]) {
Ok(LockTableType::Write { low_priority: true })
} else {
parser.expected("an lock type in LOCK TABLES", parser.peek_token())
}
}
/// UNLOCK TABLES
/// <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
fn parse_unlock_tables(_parser: &mut Parser) -> Result<Statement, ParserError> {
Ok(Statement::UnlockTables)
}

265
src/dialect/postgresql.rs Normal file
View file

@ -0,0 +1,265 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use log::debug;
use crate::dialect::{Dialect, Precedence};
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
use crate::tokenizer::Token;
/// A [`Dialect`] for [PostgreSQL](https://www.postgresql.org/)
#[derive(Debug)]
pub struct PostgreSqlDialect {}
const PERIOD_PREC: u8 = 200;
const DOUBLE_COLON_PREC: u8 = 140;
const BRACKET_PREC: u8 = 130;
const COLLATE_PREC: u8 = 120;
const AT_TZ_PREC: u8 = 110;
const CARET_PREC: u8 = 100;
const MUL_DIV_MOD_OP_PREC: u8 = 90;
const PLUS_MINUS_PREC: u8 = 80;
// there's no XOR operator in PostgreSQL, but support it here to avoid breaking tests
const XOR_PREC: u8 = 75;
const PG_OTHER_PREC: u8 = 70;
const BETWEEN_LIKE_PREC: u8 = 60;
const EQ_PREC: u8 = 50;
const IS_PREC: u8 = 40;
const NOT_PREC: u8 = 30;
const AND_PREC: u8 = 20;
const OR_PREC: u8 = 10;
impl Dialect for PostgreSqlDialect {
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
Some('"')
}
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '"' // Postgres does not support backticks to quote identifiers
}
fn is_identifier_start(&self, ch: char) -> bool {
// See https://www.postgresql.org/docs/11/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
// We don't yet support identifiers beginning with "letters with
// diacritical marks"
ch.is_alphabetic() || ch == '_'
}
fn is_identifier_part(&self, ch: char) -> bool {
ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
}
fn supports_unicode_string_literal(&self) -> bool {
true
}
/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
fn is_custom_operator_part(&self, ch: char) -> bool {
matches!(
ch,
'+' | '-'
| '*'
| '/'
| '<'
| '>'
| '='
| '~'
| '!'
| '@'
| '#'
| '%'
| '^'
| '&'
| '|'
| '`'
| '?'
)
}
fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
let token = parser.peek_token();
debug!("get_next_precedence() {token:?}");
// we only return some custom value here when the behaviour (not merely the numeric value) differs
// from the default implementation
match token.token {
Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)),
Token::LBracket => Some(Ok(BRACKET_PREC)),
Token::Arrow
| Token::LongArrow
| Token::HashArrow
| Token::HashLongArrow
| Token::AtArrow
| Token::ArrowAt
| Token::HashMinus
| Token::AtQuestion
| Token::AtAt
| Token::Question
| Token::QuestionAnd
| Token::QuestionPipe
| Token::ExclamationMark
| Token::Overlap
| Token::CaretAt
| Token::StringConcat
| Token::Sharp
| Token::ShiftRight
| Token::ShiftLeft
| Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
_ => None,
}
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
fn supports_group_by_expr(&self) -> bool {
true
}
fn prec_value(&self, prec: Precedence) -> u8 {
match prec {
Precedence::Period => PERIOD_PREC,
Precedence::DoubleColon => DOUBLE_COLON_PREC,
Precedence::AtTz => AT_TZ_PREC,
Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
Precedence::PlusMinus => PLUS_MINUS_PREC,
Precedence::Xor => XOR_PREC,
Precedence::Ampersand => PG_OTHER_PREC,
Precedence::Caret => CARET_PREC,
Precedence::Pipe => PG_OTHER_PREC,
Precedence::Between => BETWEEN_LIKE_PREC,
Precedence::Eq => EQ_PREC,
Precedence::Like => BETWEEN_LIKE_PREC,
Precedence::Is => IS_PREC,
Precedence::PgOther => PG_OTHER_PREC,
Precedence::UnaryNot => NOT_PREC,
Precedence::And => AND_PREC,
Precedence::Or => OR_PREC,
}
}
fn allow_extract_custom(&self) -> bool {
true
}
fn allow_extract_single_quotes(&self) -> bool {
true
}
fn supports_create_index_with_clause(&self) -> bool {
true
}
/// see <https://www.postgresql.org/docs/current/sql-explain.html>
fn supports_explain_with_utility_options(&self) -> bool {
true
}
/// see <https://www.postgresql.org/docs/current/sql-listen.html>
/// see <https://www.postgresql.org/docs/current/sql-unlisten.html>
/// see <https://www.postgresql.org/docs/current/sql-notify.html>
fn supports_listen_notify(&self) -> bool {
true
}
/// see <https://www.postgresql.org/docs/13/functions-math.html>
fn supports_factorial_operator(&self) -> bool {
true
}
/// see <https://www.postgresql.org/docs/current/sql-comment.html>
fn supports_comment_on(&self) -> bool {
true
}
/// See <https://www.postgresql.org/docs/current/sql-load.html>
fn supports_load_extension(&self) -> bool {
true
}
/// See <https://www.postgresql.org/docs/current/functions-json.html>
///
/// Required to support the colon in:
/// ```sql
/// SELECT json_object('a': 'b')
/// ```
fn supports_named_fn_args_with_colon_operator(&self) -> bool {
true
}
/// See <https://www.postgresql.org/docs/current/functions-json.html>
///
/// Required to support the label in:
/// ```sql
/// SELECT json_object('label': 'value')
/// ```
fn supports_named_fn_args_with_expr_name(&self) -> bool {
true
}
/// Return true if the dialect supports empty projections in SELECT statements
///
/// Example
/// ```sql
/// SELECT from table_name
/// ```
fn supports_empty_projections(&self) -> bool {
true
}
fn supports_nested_comments(&self) -> bool {
true
}
fn supports_string_escape_constant(&self) -> bool {
true
}
fn supports_numeric_literal_underscores(&self) -> bool {
true
}
/// See: <https://www.postgresql.org/docs/current/arrays.html#ARRAYS-DECLARATION>
fn supports_array_typedef_with_brackets(&self) -> bool {
true
}
fn supports_geometric_types(&self) -> bool {
true
}
fn supports_set_names(&self) -> bool {
true
}
fn supports_alter_column_type_using(&self) -> bool {
true
}
}

134
src/dialect/redshift.rs Normal file
View file

@ -0,0 +1,134 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::dialect::Dialect;
use core::iter::Peekable;
use core::str::Chars;
use super::PostgreSqlDialect;
/// A [`Dialect`] for [RedShift](https://aws.amazon.com/redshift/)
#[derive(Debug)]
pub struct RedshiftSqlDialect {}
// In most cases the redshift dialect is identical to [`PostgresSqlDialect`].
//
// Notable differences:
// 1. Redshift treats brackets `[` and `]` differently. For example, `SQL SELECT a[1][2] FROM b`
// in the Postgres dialect, the query will be parsed as an array, while in the Redshift dialect it will
// be a json path
impl Dialect for RedshiftSqlDialect {
/// Determine if a character starts a potential nested quoted identifier.
/// Example: RedShift supports the following quote styles to all mean the same thing:
/// ```sql
/// SELECT 1 AS foo;
/// SELECT 1 AS "foo";
/// SELECT 1 AS [foo];
/// SELECT 1 AS ["foo"];
/// ```
fn is_nested_delimited_identifier_start(&self, ch: char) -> bool {
ch == '['
}
/// Only applicable whenever [`Self::is_nested_delimited_identifier_start`] returns true
/// If the next sequence of tokens potentially represent a nested identifier, then this method
/// returns a tuple containing the outer quote style, and if present, the inner (nested) quote style.
///
/// Example (Redshift):
/// ```text
/// `["foo"]` => Some(`[`, Some(`"`))
/// `[foo]` => Some(`[`, None)
/// `[0]` => None
/// `"foo"` => None
/// ```
fn peek_nested_delimited_identifier_quotes(
&self,
mut chars: Peekable<Chars<'_>>,
) -> Option<(char, Option<char>)> {
if chars.peek() != Some(&'[') {
return None;
}
chars.next();
let mut not_white_chars = chars.skip_while(|ch| ch.is_whitespace()).peekable();
if let Some(&ch) = not_white_chars.peek() {
if ch == '"' {
return Some(('[', Some('"')));
}
if self.is_identifier_start(ch) {
return Some(('[', None));
}
}
None
}
fn is_identifier_start(&self, ch: char) -> bool {
// Extends Postgres dialect with sharp and UTF-8 multibyte chars
// https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
PostgreSqlDialect {}.is_identifier_start(ch) || ch == '#' || !ch.is_ascii()
}
fn is_identifier_part(&self, ch: char) -> bool {
// Extends Postgres dialect with sharp and UTF-8 multibyte chars
// https://docs.aws.amazon.com/redshift/latest/dg/r_names.html
PostgreSqlDialect {}.is_identifier_part(ch) || ch == '#' || !ch.is_ascii()
}
/// redshift has `CONVERT(type, value)` instead of `CONVERT(value, type)`
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_CONVERT_function.html>
fn convert_type_before_value(&self) -> bool {
true
}
fn supports_connect_by(&self) -> bool {
true
}
/// Redshift expects the `TOP` option before the `ALL/DISTINCT` option:
/// <https://docs.aws.amazon.com/redshift/latest/dg/r_SELECT_list.html#r_SELECT_list-parameters>
fn supports_top_before_distinct(&self) -> bool {
true
}
/// Redshift supports PartiQL: <https://docs.aws.amazon.com/redshift/latest/dg/super-overview.html>
fn supports_partiql(&self) -> bool {
true
}
fn supports_string_escape_constant(&self) -> bool {
true
}
fn supports_geometric_types(&self) -> bool {
true
}
fn supports_array_typedef_with_brackets(&self) -> bool {
true
}
fn allow_extract_single_quotes(&self) -> bool {
true
}
fn supports_string_literal_backslash_escape(&self) -> bool {
true
}
}

1234
src/dialect/snowflake.rs Normal file

File diff suppressed because it is too large Load diff

113
src/dialect/sqlite.rs Normal file
View file

@ -0,0 +1,113 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
use crate::ast::BinaryOperator;
use crate::ast::{Expr, Statement};
use crate::dialect::Dialect;
use crate::keywords::Keyword;
use crate::parser::{Parser, ParserError};
/// A [`Dialect`] for [SQLite](https://www.sqlite.org)
///
/// This dialect allows columns in a
/// [`CREATE TABLE`](https://sqlite.org/lang_createtable.html) statement with no
/// type specified, as in `CREATE TABLE t1 (a)`. In the AST, these columns will
/// have the data type [`Unspecified`](crate::ast::DataType::Unspecified).
#[derive(Debug)]
pub struct SQLiteDialect {}
impl Dialect for SQLiteDialect {
// see https://www.sqlite.org/lang_keywords.html
// parse `...`, [...] and "..." as identifier
// TODO: support depending on the context tread '...' as identifier too.
fn is_delimited_identifier_start(&self, ch: char) -> bool {
ch == '`' || ch == '"' || ch == '['
}
fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
Some('`')
}
fn is_identifier_start(&self, ch: char) -> bool {
// See https://www.sqlite.org/draft/tokenreq.html
ch.is_ascii_lowercase()
|| ch.is_ascii_uppercase()
|| ch == '_'
|| ('\u{007f}'..='\u{ffff}').contains(&ch)
}
fn supports_filter_during_aggregation(&self) -> bool {
true
}
fn supports_start_transaction_modifier(&self) -> bool {
true
}
fn is_identifier_part(&self, ch: char) -> bool {
self.is_identifier_start(ch) || ch.is_ascii_digit()
}
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
if parser.parse_keyword(Keyword::REPLACE) {
parser.prev_token();
Some(parser.parse_insert())
} else {
None
}
}
fn parse_infix(
&self,
parser: &mut crate::parser::Parser,
expr: &crate::ast::Expr,
_precedence: u8,
) -> Option<Result<crate::ast::Expr, ParserError>> {
// Parse MATCH and REGEXP as operators
// See <https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators>
for (keyword, op) in [
(Keyword::REGEXP, BinaryOperator::Regexp),
(Keyword::MATCH, BinaryOperator::Match),
] {
if parser.parse_keyword(keyword) {
let left = Box::new(expr.clone());
let right = Box::new(parser.parse_expr().unwrap());
return Some(Ok(Expr::BinaryOp { left, op, right }));
}
}
None
}
fn supports_in_empty_list(&self) -> bool {
true
}
fn supports_limit_comma(&self) -> bool {
true
}
fn supports_asc_desc_in_column_definition(&self) -> bool {
true
}
fn supports_dollar_placeholder(&self) -> bool {
true
}
}

135
src/display_utils.rs Normal file
View file

@ -0,0 +1,135 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! Utilities for formatting SQL AST nodes with pretty printing support.
//!
//! The module provides formatters that implement the `Display` trait with support
//! for both regular (`{}`) and pretty (`{:#}`) formatting modes. Pretty printing
//! adds proper indentation and line breaks to make SQL statements more readable.
use core::fmt::{self, Display, Write};
/// A wrapper around a value that adds an indent to the value when displayed with {:#}.
pub(crate) struct Indent<T>(pub T);
const INDENT: &str = " ";
impl<T> Display for Indent<T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.write_str(INDENT)?;
write!(Indent(f), "{:#}", self.0)
} else {
self.0.fmt(f)
}
}
}
/// Adds an indent to the inner writer
impl<T> Write for Indent<T>
where
T: Write,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0.write_str(s)?;
// Our NewLine and SpaceOrNewline utils always print individual newlines as a single-character string.
if s == "\n" {
self.0.write_str(INDENT)?;
}
Ok(())
}
}
/// A value that inserts a newline when displayed with {:#}, but not when displayed with {}.
pub(crate) struct NewLine;
impl Display for NewLine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.write_char('\n')
} else {
Ok(())
}
}
}
/// A value that inserts a space when displayed with {}, but a newline when displayed with {:#}.
pub(crate) struct SpaceOrNewline;
impl Display for SpaceOrNewline {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.write_char('\n')
} else {
f.write_char(' ')
}
}
}
/// A value that displays a comma-separated list of values.
/// When pretty-printed (using {:#}), it displays each value on a new line.
pub(crate) struct DisplayCommaSeparated<'a, T: fmt::Display>(pub(crate) &'a [T]);
impl<T: fmt::Display> fmt::Display for DisplayCommaSeparated<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut first = true;
for t in self.0 {
if !first {
f.write_char(',')?;
SpaceOrNewline.fmt(f)?;
}
first = false;
t.fmt(f)?;
}
Ok(())
}
}
/// Displays a whitespace, followed by a comma-separated list that is indented when pretty-printed.
pub(crate) fn indented_list<T: fmt::Display>(f: &mut fmt::Formatter, items: &[T]) -> fmt::Result {
SpaceOrNewline.fmt(f)?;
Indent(DisplayCommaSeparated(items)).fmt(f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_indent() {
struct TwoLines;
impl Display for TwoLines {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("line 1")?;
SpaceOrNewline.fmt(f)?;
f.write_str("line 2")
}
}
let indent = Indent(TwoLines);
assert_eq!(
indent.to_string(),
TwoLines.to_string(),
"Only the alternate form should be indented"
);
assert_eq!(format!("{:#}", indent), " line 1\n line 2");
}
}

1151
src/keywords.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,43 +1,179 @@
// Copyright 2018 Grove Enterprises LLC
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! SQL Parser for Rust
//! # SQL Parser for Rust
//!
//! Example code:
//! This crate provides an ANSI:SQL 2011 lexer and parser that can parse SQL
//! into an Abstract Syntax Tree ([`AST`]). See the [sqlparser crates.io page]
//! for more information.
//!
//! This crate provides an ANSI:SQL 2011 lexer and parser that can parsed SQL into an Abstract
//! Syntax Tree (AST).
//! For more information:
//! 1. [`Parser::parse_sql`] and [`Parser::new`] for the Parsing API
//! 2. [`ast`] for the AST structure
//! 3. [`Dialect`] for supported SQL dialects
//! 4. [`Spanned`] for source text locations (see "Source Spans" below for details)
//!
//! [`Spanned`]: ast::Spanned
//!
//! # Example parsing SQL text
//!
//! ```
//! use sqlparser::sqlparser::Parser;
//! use sqlparser::dialect::GenericDialect;
//! use sqlparser::parser::Parser;
//!
//! let dialect = GenericDialect {}; // or AnsiDialect
//!
//! let sql = "SELECT a, b, 123, myfunc(b) \
//! FROM table_1 \
//! WHERE a > b AND b < 100 \
//! ORDER BY a DESC, b";
//!
//! let ast = Parser::parse_sql(sql.to_string()).unwrap();
//! let ast = Parser::parse_sql(&dialect, sql).unwrap();
//!
//! println!("AST: {:?}", ast);
//! ```
//!
//! # Creating SQL text from AST
//!
//! This crate allows users to recover the original SQL text (with comments
//! removed, normalized whitespace and identifier capitalization), which is
//! useful for tools that analyze and manipulate SQL.
//!
//! ```
//! # use sqlparser::dialect::GenericDialect;
//! # use sqlparser::parser::Parser;
//! let sql = "SELECT a FROM table_1";
//!
//! // parse to a Vec<Statement>
//! let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
//!
//! // The original SQL text can be generated from the AST
//! assert_eq!(ast[0].to_string(), sql);
//! ```
//!
//! # Pretty Printing
//!
//! SQL statements can be pretty-printed with proper indentation and line breaks using the alternate flag (`{:#}`):
//!
//! ```
//! # use sqlparser::dialect::GenericDialect;
//! # use sqlparser::parser::Parser;
//! let sql = "SELECT a, b FROM table_1";
//! let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
//!
//! // Pretty print with indentation and line breaks
//! let pretty_sql = format!("{:#}", ast[0]);
//! assert_eq!(pretty_sql, r#"
//! SELECT
//! a,
//! b
//! FROM
//! table_1
//! "#.trim());
//! ```
//! [sqlparser crates.io page]: https://crates.io/crates/sqlparser
//! [`Parser::parse_sql`]: crate::parser::Parser::parse_sql
//! [`Parser::new`]: crate::parser::Parser::new
//! [`AST`]: crate::ast
//! [`ast`]: crate::ast
//! [`Dialect`]: crate::dialect::Dialect
//!
//! # Source Spans
//!
//! Starting with version `0.53.0` sqlparser introduced source spans to the
//! AST. This feature provides source information for syntax errors, enabling
//! better error messages. See [issue #1548] for more information and the
//! [`Spanned`] trait to access the spans.
//!
//! [issue #1548]: https://github.com/apache/datafusion-sqlparser-rs/issues/1548
//! [`Spanned`]: ast::Spanned
//!
//! ## Migration Guide
//!
//! For the next few releases, we will be incrementally adding source spans to the
//! AST nodes, trying to minimize the impact on existing users. Some breaking
//! changes are inevitable, and the following is a summary of the changes:
//!
//! #### New fields for spans (must be added to any existing pattern matches)
//!
//! The primary change is that new fields will be added to AST nodes to store the source `Span` or `TokenWithLocation`.
//!
//! This will require
//! 1. Adding new fields to existing pattern matches.
//! 2. Filling in the proper span information when constructing AST nodes.
//!
//! For example, since `Ident` now stores a `Span`, to construct an `Ident` you
//! must provide now provide one:
//!
//! Previously:
//! ```text
//! # use sqlparser::ast::Ident;
//! Ident {
//! value: "name".into(),
//! quote_style: None,
//! }
//! ```
//! Now
//! ```rust
//! # use sqlparser::ast::Ident;
//! # use sqlparser::tokenizer::Span;
//! Ident {
//! value: "name".into(),
//! quote_style: None,
//! span: Span::empty(),
//! };
//! ```
//!
//! Similarly, when pattern matching on `Ident`, you must now account for the
//! `span` field.
//!
//! #### Misc.
//! - [`TokenWithLocation`] stores a full `Span`, rather than just a source location.
//! Users relying on `token.location` should use `token.location.start` instead.
//!
//![`TokenWithLocation`]: tokenizer::TokenWithLocation
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::upper_case_acronyms)]
// Permit large enum variants to keep a unified, expressive AST.
// Splitting complex nodes (expressions, statements, types) into separate types
// would bloat the API and hide intent. Extra memory is a worthwhile tradeoff.
#![allow(clippy::large_enum_variant)]
extern crate fnv;
// Allow proc-macros to find this crate
extern crate self as sqlparser;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[macro_use]
extern crate lazy_static;
#[cfg(test)]
extern crate pretty_assertions;
pub mod sqlast;
pub mod sqlparser;
pub mod sqltokenizer;
pub mod ast;
#[macro_use]
pub mod dialect;
mod display_utils;
pub mod keywords;
pub mod parser;
pub mod tokenizer;
#[doc(hidden)]
// This is required to make utilities accessible by both the crate-internal
// unit-tests and by the integration tests <https://stackoverflow.com/a/44541071/1026>
// External users are not supposed to rely on this module.
pub mod test_utils;

308
src/parser/alter.rs Normal file
View file

@ -0,0 +1,308 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! SQL Parser for ALTER
#[cfg(not(feature = "std"))]
use alloc::vec;
use super::{Parser, ParserError};
use crate::{
ast::{
AlterConnectorOwner, AlterPolicyOperation, AlterRoleOperation, Expr, Password, ResetConfig,
RoleOption, SetConfigValue, Statement,
},
dialect::{MsSqlDialect, PostgreSqlDialect},
keywords::Keyword,
tokenizer::Token,
};
impl Parser<'_> {
pub fn parse_alter_role(&mut self) -> Result<Statement, ParserError> {
if dialect_of!(self is PostgreSqlDialect) {
return self.parse_pg_alter_role();
} else if dialect_of!(self is MsSqlDialect) {
return self.parse_mssql_alter_role();
}
Err(ParserError::ParserError(
"ALTER ROLE is only support for PostgreSqlDialect, MsSqlDialect".into(),
))
}
/// Parse ALTER POLICY statement
/// ```sql
/// ALTER POLICY policy_name ON table_name [ RENAME TO new_name ]
/// or
/// ALTER POLICY policy_name ON table_name
/// [ TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ]
/// [ USING ( using_expression ) ]
/// [ WITH CHECK ( check_expression ) ]
/// ```
///
/// [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterpolicy.html)
pub fn parse_alter_policy(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_identifier()?;
self.expect_keyword_is(Keyword::ON)?;
let table_name = self.parse_object_name(false)?;
if self.parse_keyword(Keyword::RENAME) {
self.expect_keyword_is(Keyword::TO)?;
let new_name = self.parse_identifier()?;
Ok(Statement::AlterPolicy {
name,
table_name,
operation: AlterPolicyOperation::Rename { new_name },
})
} else {
let to = if self.parse_keyword(Keyword::TO) {
Some(self.parse_comma_separated(|p| p.parse_owner())?)
} else {
None
};
let using = if self.parse_keyword(Keyword::USING) {
self.expect_token(&Token::LParen)?;
let expr = self.parse_expr()?;
self.expect_token(&Token::RParen)?;
Some(expr)
} else {
None
};
let with_check = if self.parse_keywords(&[Keyword::WITH, Keyword::CHECK]) {
self.expect_token(&Token::LParen)?;
let expr = self.parse_expr()?;
self.expect_token(&Token::RParen)?;
Some(expr)
} else {
None
};
Ok(Statement::AlterPolicy {
name,
table_name,
operation: AlterPolicyOperation::Apply {
to,
using,
with_check,
},
})
}
}
/// Parse an `ALTER CONNECTOR` statement
/// ```sql
/// ALTER CONNECTOR connector_name SET DCPROPERTIES(property_name=property_value, ...);
///
/// ALTER CONNECTOR connector_name SET URL new_url;
///
/// ALTER CONNECTOR connector_name SET OWNER [USER|ROLE] user_or_role;
/// ```
pub fn parse_alter_connector(&mut self) -> Result<Statement, ParserError> {
let name = self.parse_identifier()?;
self.expect_keyword_is(Keyword::SET)?;
let properties = match self.parse_options_with_keywords(&[Keyword::DCPROPERTIES])? {
properties if !properties.is_empty() => Some(properties),
_ => None,
};
let url = if self.parse_keyword(Keyword::URL) {
Some(self.parse_literal_string()?)
} else {
None
};
let owner = if self.parse_keywords(&[Keyword::OWNER, Keyword::USER]) {
let owner = self.parse_identifier()?;
Some(AlterConnectorOwner::User(owner))
} else if self.parse_keywords(&[Keyword::OWNER, Keyword::ROLE]) {
let owner = self.parse_identifier()?;
Some(AlterConnectorOwner::Role(owner))
} else {
None
};
Ok(Statement::AlterConnector {
name,
properties,
url,
owner,
})
}
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
let role_name = self.parse_identifier()?;
let operation = if self.parse_keywords(&[Keyword::ADD, Keyword::MEMBER]) {
let member_name = self.parse_identifier()?;
AlterRoleOperation::AddMember { member_name }
} else if self.parse_keywords(&[Keyword::DROP, Keyword::MEMBER]) {
let member_name = self.parse_identifier()?;
AlterRoleOperation::DropMember { member_name }
} else if self.parse_keywords(&[Keyword::WITH, Keyword::NAME]) {
if self.consume_token(&Token::Eq) {
let role_name = self.parse_identifier()?;
AlterRoleOperation::RenameRole { role_name }
} else {
return self.expected("= after WITH NAME ", self.peek_token());
}
} else {
return self.expected("'ADD' or 'DROP' or 'WITH NAME'", self.peek_token());
};
Ok(Statement::AlterRole {
name: role_name,
operation,
})
}
fn parse_pg_alter_role(&mut self) -> Result<Statement, ParserError> {
let role_name = self.parse_identifier()?;
// [ IN DATABASE _`database_name`_ ]
let in_database = if self.parse_keywords(&[Keyword::IN, Keyword::DATABASE]) {
self.parse_object_name(false).ok()
} else {
None
};
let operation = if self.parse_keyword(Keyword::RENAME) {
if self.parse_keyword(Keyword::TO) {
let role_name = self.parse_identifier()?;
AlterRoleOperation::RenameRole { role_name }
} else {
return self.expected("TO after RENAME", self.peek_token());
}
// SET
} else if self.parse_keyword(Keyword::SET) {
let config_name = self.parse_object_name(false)?;
// FROM CURRENT
if self.parse_keywords(&[Keyword::FROM, Keyword::CURRENT]) {
AlterRoleOperation::Set {
config_name,
config_value: SetConfigValue::FromCurrent,
in_database,
}
// { TO | = } { value | DEFAULT }
} else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
if self.parse_keyword(Keyword::DEFAULT) {
AlterRoleOperation::Set {
config_name,
config_value: SetConfigValue::Default,
in_database,
}
} else if let Ok(expr) = self.parse_expr() {
AlterRoleOperation::Set {
config_name,
config_value: SetConfigValue::Value(expr),
in_database,
}
} else {
self.expected("config value", self.peek_token())?
}
} else {
self.expected("'TO' or '=' or 'FROM CURRENT'", self.peek_token())?
}
// RESET
} else if self.parse_keyword(Keyword::RESET) {
if self.parse_keyword(Keyword::ALL) {
AlterRoleOperation::Reset {
config_name: ResetConfig::ALL,
in_database,
}
} else {
let config_name = self.parse_object_name(false)?;
AlterRoleOperation::Reset {
config_name: ResetConfig::ConfigName(config_name),
in_database,
}
}
// option
} else {
// [ WITH ]
let _ = self.parse_keyword(Keyword::WITH);
// option
let mut options = vec![];
while let Some(opt) = self.maybe_parse(|parser| parser.parse_pg_role_option())? {
options.push(opt);
}
// check option
if options.is_empty() {
return self.expected("option", self.peek_token())?;
}
AlterRoleOperation::WithOptions { options }
};
Ok(Statement::AlterRole {
name: role_name,
operation,
})
}
fn parse_pg_role_option(&mut self) -> Result<RoleOption, ParserError> {
let option = match self.parse_one_of_keywords(&[
Keyword::BYPASSRLS,
Keyword::NOBYPASSRLS,
Keyword::CONNECTION,
Keyword::CREATEDB,
Keyword::NOCREATEDB,
Keyword::CREATEROLE,
Keyword::NOCREATEROLE,
Keyword::INHERIT,
Keyword::NOINHERIT,
Keyword::LOGIN,
Keyword::NOLOGIN,
Keyword::PASSWORD,
Keyword::REPLICATION,
Keyword::NOREPLICATION,
Keyword::SUPERUSER,
Keyword::NOSUPERUSER,
Keyword::VALID,
]) {
Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true),
Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false),
Some(Keyword::CONNECTION) => {
self.expect_keyword_is(Keyword::LIMIT)?;
RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?))
}
Some(Keyword::CREATEDB) => RoleOption::CreateDB(true),
Some(Keyword::NOCREATEDB) => RoleOption::CreateDB(false),
Some(Keyword::CREATEROLE) => RoleOption::CreateRole(true),
Some(Keyword::NOCREATEROLE) => RoleOption::CreateRole(false),
Some(Keyword::INHERIT) => RoleOption::Inherit(true),
Some(Keyword::NOINHERIT) => RoleOption::Inherit(false),
Some(Keyword::LOGIN) => RoleOption::Login(true),
Some(Keyword::NOLOGIN) => RoleOption::Login(false),
Some(Keyword::PASSWORD) => {
let password = if self.parse_keyword(Keyword::NULL) {
Password::NullPassword
} else {
Password::Password(Expr::Value(self.parse_value()?))
};
RoleOption::Password(password)
}
Some(Keyword::REPLICATION) => RoleOption::Replication(true),
Some(Keyword::NOREPLICATION) => RoleOption::Replication(false),
Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true),
Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false),
Some(Keyword::VALID) => {
self.expect_keyword_is(Keyword::UNTIL)?;
RoleOption::ValidUntil(Expr::Value(self.parse_value()?))
}
_ => self.expected("option", self.peek_token())?,
};
Ok(option)
}
}

17174
src/parser/mod.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,185 +0,0 @@
// Copyright 2018 Grove Enterprises LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! SQL Abstract Syntax Tree (AST) types
/// SQL Abstract Syntax Tree (AST)
#[derive(Debug, Clone, PartialEq)]
pub enum ASTNode {
/// Identifier e.g. table name or column name
SQLIdentifier(String),
/// Wildcard e.g. `*`
SQLWildcard,
/// Multi part identifier e.g. `myschema.dbo.mytable`
SQLCompoundIdentifier(Vec<String>),
/// Assigment e.g. `name = 'Fred'` in an UPDATE statement
SQLAssignment(String, Box<ASTNode>),
/// `IS NULL` expression
SQLIsNull(Box<ASTNode>),
/// `IS NOT NULL` expression
SQLIsNotNull(Box<ASTNode>),
/// Binary expression e.g. `1 + 1` or `foo > bar`
SQLBinaryExpr {
left: Box<ASTNode>,
op: SQLOperator,
right: Box<ASTNode>,
},
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
SQLCast {
expr: Box<ASTNode>,
data_type: SQLType,
},
/// Nested expression e.g. `(foo > bar)` or `(1)`
SQLNested(Box<ASTNode>),
/// Unary expression
SQLUnary {
operator: SQLOperator,
rex: Box<ASTNode>,
},
/// Literal signed long
SQLLiteralLong(i64),
/// Literal floating point value
SQLLiteralDouble(f64),
/// Literal string
SQLLiteralString(String),
/// Scalar function call e.g. `LEFT(foo, 5)`
SQLFunction {
id: String,
args: Vec<ASTNode>,
},
/// Expression with ASC/DESC attribute e.g. `foo ASC` or `foo DESC`.=
SQLOrderBy {
expr: Box<ASTNode>,
asc: bool,
},
/// SELECT
SQLSelect {
/// projection expressions
projection: Vec<ASTNode>,
/// FROM
relation: Option<Box<ASTNode>>,
/// WHERE
selection: Option<Box<ASTNode>>,
/// ORDER BY
order_by: Option<Vec<ASTNode>>,
/// GROUP BY
group_by: Option<Vec<ASTNode>>,
/// HAVING
having: Option<Box<ASTNode>>,
/// LIMIT
limit: Option<Box<ASTNode>>,
},
/// INSERT
SQLInsert {
/// TABLE
table_name: String,
/// COLUMNS
columns: Vec<String>,
/// VALUES (vector of rows to insert)
values: Vec<Vec<ASTNode>>,
},
/// UPDATE
SQLUpdate {
/// TABLE
table_name: String,
/// Columns being assigned
columns: Vec<String>,
/// Values being assigned
values: Vec<ASTNode>,
/// WHERE
selection: Option<Box<ASTNode>>,
},
/// DELETE
SQLDelete {
/// FROM
relation: Option<Box<ASTNode>>,
/// WHERE
selection: Option<Box<ASTNode>>,
/// ORDER BY
order_by: Option<Vec<ASTNode>>,
limit: Option<Box<ASTNode>>,
},
/// CREATE TABLE
SQLCreateTable {
/// Table name
name: String,
/// Optional schema
columns: Vec<SQLColumnDef>,
},
}
/// SQL column definition
#[derive(Debug, Clone, PartialEq)]
pub struct SQLColumnDef {
pub name: String,
pub data_type: SQLType,
pub allow_null: bool,
}
/// SQL datatypes for literals in SQL statements
#[derive(Debug, Clone, PartialEq)]
pub enum SQLType {
/// Fixed-length character type e.g. CHAR(10)
Char(usize),
/// Variable-length character type e.g. VARCHAR(10)
Varchar(usize),
/// Large character object e.g. CLOB(1000)
Clob(usize),
/// Fixed-length binary type e.g. BINARY(10)
Binary(usize),
/// Variable-length binary type e.g. VARBINARY(10)
Varbinary(usize),
/// Large binary object e.g. BLOB(1000)
Blob(usize),
/// Decimal type with precision and optional scale e.g. DECIMAL(10,2)
Decimal(usize, Option<usize>),
/// Small integer
SmallInt,
/// Integer
Int,
/// Big integer
BigInt,
/// Floating point with optional precision e.g. FLOAT(8)
Float(Option<usize>),
/// Floating point e.g. REAL
Real,
/// Double e.g. DOUBLE PRECISION
Double,
/// Boolean
Boolean,
/// Date
Date,
/// Time
Time,
/// Timestamp
Timestamp,
}
/// SQL Operator
#[derive(Debug, PartialEq, Clone)]
pub enum SQLOperator {
Plus,
Minus,
Multiply,
Divide,
Modulus,
Gt,
Lt,
GtEq,
LtEq,
Eq,
NotEq,
And,
Or,
}

View file

@ -1,971 +0,0 @@
// Copyright 2018 Grove Enterprises LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! SQL Parser
use super::sqlast::*;
use super::sqltokenizer::*;
#[derive(Debug, Clone)]
pub enum ParserError {
TokenizerError(String),
ParserError(String),
}
macro_rules! parser_err {
($MSG:expr) => {
Err(ParserError::ParserError($MSG.to_string()))
};
}
impl From<TokenizerError> for ParserError {
fn from(e: TokenizerError) -> Self {
ParserError::TokenizerError(format!("{:?}", e))
}
}
/// SQL Parser
pub struct Parser {
tokens: Vec<Token>,
index: usize,
}
impl Parser {
/// Parse the specified tokens
pub fn new(tokens: Vec<Token>) -> Self {
Parser {
tokens: tokens,
index: 0,
}
}
/// Parse a SQL statement and produce an Abstract Syntax Tree (AST)
pub fn parse_sql(sql: String) -> Result<ASTNode, ParserError> {
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize()?;
let mut parser = Parser::new(tokens);
parser.parse()
}
/// Parse a new expression
pub fn parse(&mut self) -> Result<ASTNode, ParserError> {
self.parse_expr(0)
}
/// Parse tokens until the precedence changes
pub fn parse_expr(&mut self, precedence: u8) -> Result<ASTNode, ParserError> {
let mut expr = self.parse_prefix()?;
loop {
let next_precedence = self.get_next_precedence()?;
if precedence >= next_precedence {
break;
}
if let Some(infix_expr) = self.parse_infix(expr.clone(), next_precedence)? {
expr = infix_expr;
}
}
Ok(expr)
}
/// Parse an expression prefix
pub fn parse_prefix(&mut self) -> Result<ASTNode, ParserError> {
match self.next_token() {
Some(t) => {
match t {
Token::Keyword(k) => match k.to_uppercase().as_ref() {
"SELECT" => Ok(self.parse_select()?),
"CREATE" => Ok(self.parse_create()?),
"DELETE" => Ok(self.parse_delete()?),
_ => return parser_err!(format!("No prefix parser for keyword {}", k)),
},
Token::Mult => Ok(ASTNode::SQLWildcard),
Token::Identifier(id) => {
match self.peek_token() {
Some(Token::LParen) => {
self.next_token(); // skip lparen
match id.to_uppercase().as_ref() {
"CAST" => self.parse_cast_expression(),
_ => {
let args = self.parse_expr_list()?;
self.next_token(); // skip rparen
Ok(ASTNode::SQLFunction { id, args })
}
}
}
Some(Token::Period) => {
let mut id_parts: Vec<String> = vec![id];
while self.peek_token() == Some(Token::Period) {
self.consume_token(&Token::Period)?;
match self.next_token() {
Some(Token::Identifier(id)) => id_parts.push(id),
_ => {
return parser_err!(format!(
"Error parsing compound identifier"
))
}
}
}
Ok(ASTNode::SQLCompoundIdentifier(id_parts))
}
_ => Ok(ASTNode::SQLIdentifier(id)),
}
}
Token::Number(ref n) if n.contains(".") => match n.parse::<f64>() {
Ok(n) => Ok(ASTNode::SQLLiteralDouble(n)),
Err(e) => parser_err!(format!("Could not parse '{}' as i64: {}", n, e)),
},
Token::Number(ref n) => match n.parse::<i64>() {
Ok(n) => Ok(ASTNode::SQLLiteralLong(n)),
Err(e) => parser_err!(format!("Could not parse '{}' as i64: {}", n, e)),
},
Token::String(ref s) => Ok(ASTNode::SQLLiteralString(s.to_string())),
_ => parser_err!(format!(
"Prefix parser expected a keyword but found {:?}",
t
)),
}
}
None => parser_err!(format!("Prefix parser expected a keyword but hit EOF")),
}
}
/// Parse a SQL CAST function e.g. `CAST(expr AS FLOAT)`
pub fn parse_cast_expression(&mut self) -> Result<ASTNode, ParserError> {
let expr = self.parse_expr(0)?;
self.consume_token(&Token::Keyword("AS".to_string()))?;
let data_type = self.parse_data_type()?;
self.consume_token(&Token::RParen)?;
Ok(ASTNode::SQLCast {
expr: Box::new(expr),
data_type,
})
}
/// Parse an expression infix (typically an operator)
pub fn parse_infix(
&mut self,
expr: ASTNode,
precedence: u8,
) -> Result<Option<ASTNode>, ParserError> {
match self.next_token() {
Some(tok) => match tok {
Token::Keyword(ref k) => if k == "IS" {
if self.parse_keywords(vec!["NULL"]) {
Ok(Some(ASTNode::SQLIsNull(Box::new(expr))))
} else if self.parse_keywords(vec!["NOT", "NULL"]) {
Ok(Some(ASTNode::SQLIsNotNull(Box::new(expr))))
} else {
parser_err!("Invalid tokens after IS")
}
} else {
Ok(Some(ASTNode::SQLBinaryExpr {
left: Box::new(expr),
op: self.to_sql_operator(&tok)?,
right: Box::new(self.parse_expr(precedence)?),
}))
},
Token::Eq
| Token::Neq
| Token::Gt
| Token::GtEq
| Token::Lt
| Token::LtEq
| Token::Plus
| Token::Minus
| Token::Mult
| Token::Mod
| Token::Div => Ok(Some(ASTNode::SQLBinaryExpr {
left: Box::new(expr),
op: self.to_sql_operator(&tok)?,
right: Box::new(self.parse_expr(precedence)?),
})),
_ => parser_err!(format!("No infix parser for token {:?}", tok)),
},
None => Ok(None),
}
}
/// Convert a token operator to an AST operator
pub fn to_sql_operator(&self, tok: &Token) -> Result<SQLOperator, ParserError> {
match tok {
&Token::Eq => Ok(SQLOperator::Eq),
&Token::Neq => Ok(SQLOperator::NotEq),
&Token::Lt => Ok(SQLOperator::Lt),
&Token::LtEq => Ok(SQLOperator::LtEq),
&Token::Gt => Ok(SQLOperator::Gt),
&Token::GtEq => Ok(SQLOperator::GtEq),
&Token::Plus => Ok(SQLOperator::Plus),
&Token::Minus => Ok(SQLOperator::Minus),
&Token::Mult => Ok(SQLOperator::Multiply),
&Token::Div => Ok(SQLOperator::Divide),
&Token::Mod => Ok(SQLOperator::Modulus),
&Token::Keyword(ref k) if k == "AND" => Ok(SQLOperator::And),
&Token::Keyword(ref k) if k == "OR" => Ok(SQLOperator::Or),
_ => parser_err!(format!("Unsupported SQL operator {:?}", tok)),
}
}
/// Get the precedence of the next token
pub fn get_next_precedence(&self) -> Result<u8, ParserError> {
if self.index < self.tokens.len() {
self.get_precedence(&self.tokens[self.index])
} else {
Ok(0)
}
}
/// Get the precedence of a token
pub fn get_precedence(&self, tok: &Token) -> Result<u8, ParserError> {
//println!("get_precedence() {:?}", tok);
match tok {
&Token::Keyword(ref k) if k == "OR" => Ok(5),
&Token::Keyword(ref k) if k == "AND" => Ok(10),
&Token::Keyword(ref k) if k == "IS" => Ok(15),
&Token::Eq | &Token::Lt | &Token::LtEq | &Token::Neq | &Token::Gt | &Token::GtEq => {
Ok(20)
}
&Token::Plus | &Token::Minus => Ok(30),
&Token::Mult | &Token::Div | &Token::Mod => Ok(40),
_ => Ok(0),
}
}
/// Peek at the next token
pub fn peek_token(&mut self) -> Option<Token> {
if self.index < self.tokens.len() {
Some(self.tokens[self.index].clone())
} else {
None
}
}
/// Get the next token and increment the token index
pub fn next_token(&mut self) -> Option<Token> {
if self.index < self.tokens.len() {
self.index = self.index + 1;
Some(self.tokens[self.index - 1].clone())
} else {
None
}
}
/// Get the previous token and decrement the token index
pub fn prev_token(&mut self) -> Option<Token> {
if self.index > 0 {
Some(self.tokens[self.index - 1].clone())
} else {
None
}
}
/// Look for an expected keyword and consume it if it exists
pub fn parse_keyword(&mut self, expected: &'static str) -> bool {
match self.peek_token() {
Some(Token::Keyword(k)) => {
if expected.eq_ignore_ascii_case(k.as_str()) {
self.next_token();
true
} else {
false
}
}
_ => false,
}
}
/// Look for an expected sequence of keywords and consume them if they exist
pub fn parse_keywords(&mut self, keywords: Vec<&'static str>) -> bool {
let index = self.index;
for keyword in keywords {
//println!("parse_keywords aborting .. expecting {}", keyword);
if !self.parse_keyword(&keyword) {
//println!("parse_keywords aborting .. did not find {}", keyword);
// reset index and return immediately
self.index = index;
return false;
}
}
true
}
//TODO: this function is inconsistent and sometimes returns bool and sometimes fails
/// Consume the next token if it matches the expected token, otherwise return an error
pub fn consume_token(&mut self, expected: &Token) -> Result<bool, ParserError> {
match self.peek_token() {
Some(ref t) => if *t == *expected {
self.next_token();
Ok(true)
} else {
Ok(false)
},
_ => parser_err!(format!(
"expected token {:?} but was {:?}",
expected,
self.prev_token()
)),
}
}
/// Parse a SQL CREATE statement
pub fn parse_create(&mut self) -> Result<ASTNode, ParserError> {
if self.parse_keywords(vec!["TABLE"]) {
match self.next_token() {
Some(Token::Identifier(id)) => {
// parse optional column list (schema)
let mut columns = vec![];
if self.consume_token(&Token::LParen)? {
loop {
if let Some(Token::Identifier(column_name)) = self.next_token() {
if let Ok(data_type) = self.parse_data_type() {
let allow_null = if self.parse_keywords(vec!["NOT", "NULL"]) {
false
} else if self.parse_keyword("NULL") {
true
} else {
true
};
match self.peek_token() {
Some(Token::Comma) => {
self.next_token();
columns.push(SQLColumnDef {
name: column_name,
data_type: data_type,
allow_null,
});
}
Some(Token::RParen) => {
self.next_token();
columns.push(SQLColumnDef {
name: column_name,
data_type: data_type,
allow_null,
});
break;
}
_ => {
return parser_err!(
"Expected ',' or ')' after column definition"
);
}
}
} else {
return parser_err!(
"Error parsing data type in column definition"
);
}
} else {
return parser_err!("Error parsing column name");
}
}
}
Ok(ASTNode::SQLCreateTable { name: id, columns })
}
_ => parser_err!(format!(
"Unexpected token after CREATE EXTERNAL TABLE: {:?}",
self.peek_token()
)),
}
} else {
parser_err!(format!(
"Unexpected token after CREATE: {:?}",
self.peek_token()
))
}
}
/// Parse a literal integer/long
pub fn parse_literal_int(&mut self) -> Result<i64, ParserError> {
match self.next_token() {
Some(Token::Number(s)) => s.parse::<i64>().map_err(|e| {
ParserError::ParserError(format!("Could not parse '{}' as i64: {}", s, e))
}),
other => parser_err!(format!("Expected literal int, found {:?}", other)),
}
}
/// Parse a literal string
pub fn parse_literal_string(&mut self) -> Result<String, ParserError> {
match self.next_token() {
Some(Token::String(ref s)) => Ok(s.clone()),
other => parser_err!(format!("Expected literal string, found {:?}", other)),
}
}
/// Parse a SQL datatype (in the context of a CREATE TABLE statement for example)
pub fn parse_data_type(&mut self) -> Result<SQLType, ParserError> {
match self.next_token() {
Some(Token::Keyword(k)) => match k.to_uppercase().as_ref() {
"BOOLEAN" => Ok(SQLType::Boolean),
"FLOAT" => Ok(SQLType::Float(self.parse_optional_precision()?)),
"REAL" => Ok(SQLType::Real),
"DOUBLE" => Ok(SQLType::Double),
"SMALLINT" => Ok(SQLType::SmallInt),
"INT" | "INTEGER" => Ok(SQLType::Int),
"BIGINT" => Ok(SQLType::BigInt),
"VARCHAR" => Ok(SQLType::Varchar(self.parse_precision()?)),
_ => parser_err!(format!("Invalid data type '{:?}'", k)),
},
other => parser_err!(format!("Invalid data type: '{:?}'", other)),
}
}
pub fn parse_precision(&mut self) -> Result<usize, ParserError> {
//TODO: error handling
Ok(self.parse_optional_precision()?.unwrap())
}
pub fn parse_optional_precision(&mut self) -> Result<Option<usize>, ParserError> {
if self.consume_token(&Token::LParen)? {
let n = self.parse_literal_int()?;
//TODO: check return value of reading rparen
self.consume_token(&Token::RParen)?;
Ok(Some(n as usize))
} else {
Ok(None)
}
}
pub fn parse_delete(&mut self) -> Result<ASTNode, ParserError> {
let relation: Option<Box<ASTNode>> = if self.parse_keyword("FROM") {
Some(Box::new(self.parse_expr(0)?))
} else {
None
};
let order_by = if self.parse_keywords(vec!["ORDER", "BY"]) {
Some(self.parse_order_by_expr_list()?)
} else {
None
};
let limit = if self.parse_keyword("LIMIT") {
self.parse_limit()?
} else {
None
};
let selection = if self.parse_keyword("WHERE") {
Some(Box::new(self.parse_expr(0)?))
} else {
None
};
// parse next token
if let Some(next_token) = self.peek_token() {
parser_err!(format!(
"Unexpected token at end of DELETE: {:?}",
next_token
))
} else {
Ok(ASTNode::SQLDelete {
relation,
selection,
order_by,
limit,
})
}
}
/// Parse a SELECT statement
pub fn parse_select(&mut self) -> Result<ASTNode, ParserError> {
let projection = self.parse_expr_list()?;
let relation: Option<Box<ASTNode>> = if self.parse_keyword("FROM") {
//TODO: add support for JOIN
Some(Box::new(self.parse_expr(0)?))
} else {
None
};
let selection = if self.parse_keyword("WHERE") {
Some(Box::new(self.parse_expr(0)?))
} else {
None
};
let group_by = if self.parse_keywords(vec!["GROUP", "BY"]) {
Some(self.parse_expr_list()?)
} else {
None
};
let having = if self.parse_keyword("HAVING") {
Some(Box::new(self.parse_expr(0)?))
} else {
None
};
let order_by = if self.parse_keywords(vec!["ORDER", "BY"]) {
Some(self.parse_order_by_expr_list()?)
} else {
None
};
let limit = if self.parse_keyword("LIMIT") {
self.parse_limit()?
} else {
None
};
if let Some(next_token) = self.peek_token() {
parser_err!(format!(
"Unexpected token at end of SELECT: {:?}",
next_token
))
} else {
Ok(ASTNode::SQLSelect {
projection,
selection,
relation,
limit,
order_by,
group_by,
having,
})
}
}
/// Parse a comma-delimited list of SQL expressions
pub fn parse_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
let mut expr_list: Vec<ASTNode> = vec![];
loop {
expr_list.push(self.parse_expr(0)?);
if let Some(t) = self.peek_token() {
if t == Token::Comma {
self.next_token();
} else {
break;
}
} else {
//EOF
break;
}
}
Ok(expr_list)
}
/// Parse a comma-delimited list of SQL ORDER BY expressions
pub fn parse_order_by_expr_list(&mut self) -> Result<Vec<ASTNode>, ParserError> {
let mut expr_list: Vec<ASTNode> = vec![];
loop {
let expr = self.parse_expr(0)?;
// look for optional ASC / DESC specifier
let asc = match self.peek_token() {
Some(Token::Keyword(k)) => {
self.next_token(); // consume it
match k.to_uppercase().as_ref() {
"ASC" => true,
"DESC" => false,
_ => {
return parser_err!(format!(
"Invalid modifier for ORDER BY expression: {:?}",
k
))
}
}
}
Some(Token::Comma) => true,
Some(other) => {
return parser_err!(format!("Unexpected token after ORDER BY expr: {:?}", other))
}
None => true,
};
expr_list.push(ASTNode::SQLOrderBy {
expr: Box::new(expr),
asc,
});
if let Some(t) = self.peek_token() {
if t == Token::Comma {
self.next_token();
} else {
break;
}
} else {
// EOF
break;
}
}
Ok(expr_list)
}
/// Parse a LIMIT clause
pub fn parse_limit(&mut self) -> Result<Option<Box<ASTNode>>, ParserError> {
if self.parse_keyword("ALL") {
Ok(None)
} else {
self.parse_literal_int()
.map(|n| Some(Box::new(ASTNode::SQLLiteralLong(n))))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_delete_statement() {
let sql: &str = "DELETE FROM 'table'";
match parse_sql(&sql) {
ASTNode::SQLDelete {
relation,
..
} => {
assert_eq!(Some(Box::new(ASTNode::SQLLiteralString("table".to_string()))), relation);
},
_ => assert!(false),
}
}
#[test]
fn parse_where_delete_statement() {
let sql: &str = "DELETE FROM 'table' WHERE name = 5";
use self::ASTNode::*;
use self::SQLOperator::*;
match parse_sql(&sql) {
ASTNode::SQLDelete {
relation,
selection,
..
} => {
assert_eq!(Some(Box::new(ASTNode::SQLLiteralString("table".to_string()))), relation);
assert_eq!(
SQLBinaryExpr {
left: Box::new(SQLIdentifier("name".to_string())),
op: Eq,
right: Box::new(SQLLiteralLong(5)),
},
*selection.unwrap(),
);
},
_ => assert!(false),
}
}
#[test]
fn parse_simple_select() {
let sql = String::from("SELECT id, fname, lname FROM customer WHERE id = 1 LIMIT 5");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect {
projection, limit, ..
} => {
assert_eq!(3, projection.len());
assert_eq!(Some(Box::new(ASTNode::SQLLiteralLong(5))), limit);
}
_ => assert!(false),
}
}
#[test]
fn parse_select_wildcard() {
let sql = String::from("SELECT * FROM customer");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect { projection, .. } => {
assert_eq!(1, projection.len());
assert_eq!(ASTNode::SQLWildcard, projection[0]);
}
_ => assert!(false),
}
}
#[test]
fn parse_select_count_wildcard() {
let sql = String::from("SELECT COUNT(*) FROM customer");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect { projection, .. } => {
assert_eq!(1, projection.len());
assert_eq!(
ASTNode::SQLFunction {
id: "COUNT".to_string(),
args: vec![ASTNode::SQLWildcard],
},
projection[0]
);
}
_ => assert!(false),
}
}
#[test]
fn parse_select_string_predicate() {
let sql = String::from(
"SELECT id, fname, lname FROM customer \
WHERE salary != 'Not Provided' AND salary != ''",
);
let _ast = parse_sql(&sql);
//TODO: add assertions
}
#[test]
fn parse_projection_nested_type() {
let sql = String::from("SELECT customer.address.state FROM foo");
let _ast = parse_sql(&sql);
//TODO: add assertions
}
#[test]
fn parse_compound_expr_1() {
use self::ASTNode::*;
use self::SQLOperator::*;
let sql = String::from("a + b * c");
let ast = parse_sql(&sql);
assert_eq!(
SQLBinaryExpr {
left: Box::new(SQLIdentifier("a".to_string())),
op: Plus,
right: Box::new(SQLBinaryExpr {
left: Box::new(SQLIdentifier("b".to_string())),
op: Multiply,
right: Box::new(SQLIdentifier("c".to_string()))
})
},
ast
);
}
#[test]
fn parse_compound_expr_2() {
use self::ASTNode::*;
use self::SQLOperator::*;
let sql = String::from("a * b + c");
let ast = parse_sql(&sql);
assert_eq!(
SQLBinaryExpr {
left: Box::new(SQLBinaryExpr {
left: Box::new(SQLIdentifier("a".to_string())),
op: Multiply,
right: Box::new(SQLIdentifier("b".to_string()))
}),
op: Plus,
right: Box::new(SQLIdentifier("c".to_string()))
},
ast
);
}
#[test]
fn parse_is_null() {
use self::ASTNode::*;
let sql = String::from("a IS NULL");
let ast = parse_sql(&sql);
assert_eq!(SQLIsNull(Box::new(SQLIdentifier("a".to_string()))), ast);
}
#[test]
fn parse_is_not_null() {
use self::ASTNode::*;
let sql = String::from("a IS NOT NULL");
let ast = parse_sql(&sql);
assert_eq!(SQLIsNotNull(Box::new(SQLIdentifier("a".to_string()))), ast);
}
#[test]
fn parse_select_order_by() {
let sql = String::from(
"SELECT id, fname, lname FROM customer WHERE id < 5 ORDER BY lname ASC, fname DESC",
);
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect { order_by, .. } => {
assert_eq!(
Some(vec![
ASTNode::SQLOrderBy {
expr: Box::new(ASTNode::SQLIdentifier("lname".to_string())),
asc: true,
},
ASTNode::SQLOrderBy {
expr: Box::new(ASTNode::SQLIdentifier("fname".to_string())),
asc: false,
},
]),
order_by
);
}
_ => assert!(false),
}
}
#[test]
fn parse_select_group_by() {
let sql = String::from("SELECT id, fname, lname FROM customer GROUP BY lname, fname");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect { group_by, .. } => {
assert_eq!(
Some(vec![
ASTNode::SQLIdentifier("lname".to_string()),
ASTNode::SQLIdentifier("fname".to_string()),
]),
group_by
);
}
_ => assert!(false),
}
}
#[test]
fn parse_limit_accepts_all() {
let sql = String::from("SELECT id, fname, lname FROM customer WHERE id = 1 LIMIT ALL");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect {
projection, limit, ..
} => {
assert_eq!(3, projection.len());
assert_eq!(None, limit);
}
_ => assert!(false),
}
}
#[test]
fn parse_cast() {
let sql = String::from("SELECT CAST(id AS BIGINT) FROM customer");
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLSelect { projection, .. } => {
assert_eq!(1, projection.len());
assert_eq!(
ASTNode::SQLCast {
expr: Box::new(ASTNode::SQLIdentifier("id".to_string())),
data_type: SQLType::BigInt
},
projection[0]
);
}
_ => assert!(false),
}
}
#[test]
fn parse_create_table() {
let sql = String::from(
"CREATE TABLE uk_cities (\
name VARCHAR(100) NOT NULL,\
lat DOUBLE NULL,\
lng DOUBLE NULL)",
);
let ast = parse_sql(&sql);
match ast {
ASTNode::SQLCreateTable { name, columns } => {
assert_eq!("uk_cities", name);
assert_eq!(3, columns.len());
let c_name = &columns[0];
assert_eq!("name", c_name.name);
assert_eq!(SQLType::Varchar(100), c_name.data_type);
assert_eq!(false, c_name.allow_null);
let c_lat = &columns[1];
assert_eq!("lat", c_lat.name);
assert_eq!(SQLType::Double, c_lat.data_type);
assert_eq!(true, c_lat.allow_null);
let c_lng = &columns[2];
assert_eq!("lng", c_lng.name);
assert_eq!(SQLType::Double, c_lng.data_type);
assert_eq!(true, c_lng.allow_null);
}
_ => assert!(false),
}
}
#[test]
fn parse_scalar_function_in_projection() {
let sql = String::from("SELECT sqrt(id) FROM foo");
let ast = parse_sql(&sql);
if let ASTNode::SQLSelect { projection, .. } = ast {
assert_eq!(
vec![ASTNode::SQLFunction {
id: String::from("sqrt"),
args: vec![ASTNode::SQLIdentifier(String::from("id"))],
}],
projection
);
} else {
assert!(false);
}
}
#[test]
fn parse_aggregate_with_group_by() {
let sql = String::from("SELECT a, COUNT(1), MIN(b), MAX(b) FROM foo GROUP BY a");
let _ast = parse_sql(&sql);
//TODO: assertions
}
#[test]
fn parse_literal_string() {
let sql = "SELECT 'one'";
match parse_sql(&sql) {
ASTNode::SQLSelect { ref projection, .. } => {
assert_eq!(
projection[0],
ASTNode::SQLLiteralString("one".to_string())
);
}
_ => panic!(),
}
}
#[test]
fn parse_select_version() {
let sql = "SELECT @@version";
match parse_sql(&sql) {
ASTNode::SQLSelect { ref projection, .. } => {
assert_eq!(
projection[0],
ASTNode::SQLIdentifier("@@version".to_string())
);
}
_ => panic!(),
}
}
fn parse_sql(sql: &str) -> ASTNode {
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let mut parser = Parser::new(tokens);
let ast = parser.parse().unwrap();
ast
}
}

View file

@ -1,481 +0,0 @@
// Copyright 2018 Grove Enterprises LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! SQL Tokenizer
use std::iter::Peekable;
use std::str::Chars;
use fnv::FnvHashSet;
/// SQL Token enumeration
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
/// SQL identifier e.g. table or column name
Identifier(String),
/// SQL keyword e.g. Keyword("SELECT")
Keyword(String),
/// Numeric literal
Number(String),
/// String literal
String(String),
/// Comma
Comma,
/// Whitespace (space, tab, etc)
Whitespace(char),
/// Equality operator `=`
Eq,
/// Not Equals operator `!=` or `<>`
Neq,
/// Less Than operator `<`
Lt,
/// Greater han operator `>`
Gt,
/// Less Than Or Equals operator `<=`
LtEq,
/// Greater Than Or Equals operator `>=`
GtEq,
/// Plus operator `+`
Plus,
/// Minus operator `-`
Minus,
/// Multiplication operator `*`
Mult,
/// Division operator `/`
Div,
/// Modulo Operator `%`
Mod,
/// Left parenthesis `(`
LParen,
/// Right parenthesis `)`
RParen,
/// Period (used for compound identifiers or projections into nested types)
Period,
}
/// Tokenizer error
#[derive(Debug, PartialEq)]
pub struct TokenizerError(String);
lazy_static! {
static ref KEYWORDS: FnvHashSet<&'static str> = {
let mut m = FnvHashSet::default();
m.insert("SELECT");
m.insert("FROM");
m.insert("WHERE");
m.insert("LIMIT");
m.insert("ORDER");
m.insert("GROUP");
m.insert("BY");
m.insert("HAVING");
m.insert("UNION");
m.insert("ALL");
m.insert("INSERT");
m.insert("UPDATE");
m.insert("DELETE");
m.insert("IN");
m.insert("IS");
m.insert("NULL");
m.insert("SET");
m.insert("CREATE");
m.insert("EXTERNAL");
m.insert("TABLE");
m.insert("ASC");
m.insert("DESC");
m.insert("AND");
m.insert("OR");
m.insert("NOT");
m.insert("AS");
m.insert("STORED");
m.insert("CSV");
m.insert("PARQUET");
m.insert("LOCATION");
m.insert("WITH");
m.insert("WITHOUT");
m.insert("HEADER");
m.insert("ROW");
// SQL types
m.insert("CHAR");
m.insert("CHARACTER");
m.insert("VARYING");
m.insert("LARGE");
m.insert("OBJECT");
m.insert("VARCHAR");
m.insert("CLOB");
m.insert("BINARY");
m.insert("VARBINARY");
m.insert("BLOB");
m.insert("FLOAT");
m.insert("REAL");
m.insert("DOUBLE");
m.insert("PRECISION");
m.insert("INT");
m.insert("INTEGER");
m.insert("SMALLINT");
m.insert("BIGINT");
m.insert("NUMERIC");
m.insert("DECIMAL");
m.insert("DEC");
m.insert("BOOLEAN");
m.insert("DATE");
m.insert("TIME");
m.insert("TIMESTAMP");
m
};
}
/// SQL Tokenizer
pub struct Tokenizer {
pub query: String,
pub line: u64,
pub col: u64,
}
impl Tokenizer {
/// Create a new SQL tokenizer for the specified SQL statement
pub fn new(query: &str) -> Self {
Self {
query: query.to_string(),
line: 1,
col: 1,
}
}
/// Tokenize the statement and produce a vector of tokens
pub fn tokenize(&mut self) -> Result<Vec<Token>, TokenizerError> {
let mut peekable = self.query.chars().peekable();
let mut tokens: Vec<Token> = vec![];
while let Some(token) = self.next_token(&mut peekable)? {
match &token {
Token::Whitespace('\n') => {
self.line += 1;
self.col = 1;
},
Token::Whitespace('\t') => self.col += 4,
Token::Identifier(s) => self.col += s.len() as u64,
Token::Keyword(s) => self.col += s.len() as u64,
Token::Number(s) => self.col += s.len() as u64,
Token::String(s) => self.col += s.len() as u64,
_ => self.col += 1,
}
tokens.push(token);
}
Ok(tokens
.into_iter()
.filter(|t| match t {
Token::Whitespace(..) => false,
_ => true,
}).collect())
}
/// Get the next token or return None
fn next_token(&self, chars: &mut Peekable<Chars>) -> Result<Option<Token>, TokenizerError> {
//println!("next_token: {:?}", chars.peek());
match chars.peek() {
Some(&ch) => match ch {
// whitespace
' ' | '\t' | '\n' => {
chars.next(); // consume
Ok(Some(Token::Whitespace(ch)))
}
// identifier or keyword
'a'...'z' | 'A'...'Z' | '_' | '@' => {
let mut s = String::new();
while let Some(&ch) = chars.peek() {
match ch {
'a'...'z' | 'A'...'Z' | '_' | '0'...'9' | '@' => {
chars.next(); // consume
s.push(ch);
}
_ => break,
}
}
let upper_str = s.to_uppercase();
if KEYWORDS.contains(upper_str.as_str()) {
Ok(Some(Token::Keyword(upper_str)))
} else {
Ok(Some(Token::Identifier(s)))
}
}
// string
'\'' => {
//TODO: handle escaped quotes in string
//TODO: handle EOF before terminating quote
let mut s = String::new();
chars.next(); // consume
while let Some(&ch) = chars.peek() {
match ch {
'\'' => {
chars.next(); // consume
break;
}
_ => {
chars.next(); // consume
s.push(ch);
}
}
}
Ok(Some(Token::String(s)))
}
// numbers
'0'...'9' => {
let mut s = String::new();
while let Some(&ch) = chars.peek() {
match ch {
'0'...'9' | '.' => {
chars.next(); // consume
s.push(ch);
}
_ => break,
}
}
Ok(Some(Token::Number(s)))
}
// punctuation
',' => {
chars.next();
Ok(Some(Token::Comma))
}
'(' => {
chars.next();
Ok(Some(Token::LParen))
}
')' => {
chars.next();
Ok(Some(Token::RParen))
}
// operators
'+' => {
chars.next();
Ok(Some(Token::Plus))
}
'-' => {
chars.next();
Ok(Some(Token::Minus))
}
'*' => {
chars.next();
Ok(Some(Token::Mult))
}
'/' => {
chars.next();
Ok(Some(Token::Div))
}
'%' => {
chars.next();
Ok(Some(Token::Mod))
}
'=' => {
chars.next();
Ok(Some(Token::Eq))
}
'.' => {
chars.next();
Ok(Some(Token::Period))
}
'!' => {
chars.next(); // consume
match chars.peek() {
Some(&ch) => match ch {
'=' => {
chars.next();
Ok(Some(Token::Neq))
}
_ => Err(TokenizerError(format!("Tokenizer Error at Line: {}, Col: {}", self.line, self.col))),
},
None => Err(TokenizerError(format!("Tokenizer Error at Line: {}, Col: {}", self.line, self.col))),
}
}
'<' => {
chars.next(); // consume
match chars.peek() {
Some(&ch) => match ch {
'=' => {
chars.next();
Ok(Some(Token::LtEq))
}
'>' => {
chars.next();
Ok(Some(Token::Neq))
}
_ => Ok(Some(Token::Lt)),
},
None => Ok(Some(Token::Lt)),
}
}
'>' => {
chars.next(); // consume
match chars.peek() {
Some(&ch) => match ch {
'=' => {
chars.next();
Ok(Some(Token::GtEq))
}
_ => Ok(Some(Token::Gt)),
},
None => Ok(Some(Token::Gt)),
}
}
_ => Err(TokenizerError(format!(
"Tokenizer Error at Line: {}, Column: {}, unhandled char '{}'",
self.line,
self.col,
ch
))),
},
None => Ok(None),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tokenize_select_1() {
let sql = String::from("SELECT 1");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::Keyword(String::from("SELECT")),
Token::Number(String::from("1")),
];
compare(expected, tokens);
}
#[test]
fn tokenize_scalar_function() {
let sql = String::from("SELECT sqrt(1)");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::Keyword(String::from("SELECT")),
Token::Identifier(String::from("sqrt")),
Token::LParen,
Token::Number(String::from("1")),
Token::RParen,
];
compare(expected, tokens);
}
#[test]
fn tokenize_simple_select() {
let sql = String::from("SELECT * FROM customer WHERE id = 1 LIMIT 5");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::Keyword(String::from("SELECT")),
Token::Mult,
Token::Keyword(String::from("FROM")),
Token::Identifier(String::from("customer")),
Token::Keyword(String::from("WHERE")),
Token::Identifier(String::from("id")),
Token::Eq,
Token::Number(String::from("1")),
Token::Keyword(String::from("LIMIT")),
Token::Number(String::from("5")),
];
compare(expected, tokens);
}
#[test]
fn tokenize_string_predicate() {
let sql = String::from("SELECT * FROM customer WHERE salary != 'Not Provided'");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::Keyword(String::from("SELECT")),
Token::Mult,
Token::Keyword(String::from("FROM")),
Token::Identifier(String::from("customer")),
Token::Keyword(String::from("WHERE")),
Token::Identifier(String::from("salary")),
Token::Neq,
Token::String(String::from("Not Provided")),
];
compare(expected, tokens);
}
#[test]
fn tokenize_invalid_string() {
let sql = String::from("\nمصطفىh");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize();
match tokens {
Err(e) => assert_eq!(TokenizerError("Tokenizer Error at Line: 2, Column: 1, unhandled char \'م\'".to_string()), e),
_ => panic!("Test Failure in tokenize_invalid_string"),
}
}
#[test]
fn tokenize_invalid_string_cols() {
let sql = String::from("\n\nSELECT * FROM table\tمصطفىh");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize();
match tokens {
Err(e) => assert_eq!(TokenizerError("Tokenizer Error at Line: 3, Column: 24, unhandled char \'م\'".to_string()), e),
_ => panic!("Test Failure in tokenize_invalid_string_cols"),
}
}
#[test]
fn tokenize_is_null() {
let sql = String::from("a IS NULL");
let mut tokenizer = Tokenizer::new(&sql);
let tokens = tokenizer.tokenize().unwrap();
let expected = vec![
Token::Identifier(String::from("a")),
Token::Keyword("IS".to_string()),
Token::Keyword("NULL".to_string()),
];
compare(expected, tokens);
}
fn compare(expected: Vec<Token>, actual: Vec<Token>) {
//println!("------------------------------");
//println!("tokens = {:?}", actual);
//println!("expected = {:?}", expected);
//println!("------------------------------");
assert_eq!(expected, actual);
}
}

504
src/test_utils.rs Normal file
View file

@ -0,0 +1,504 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/// This module contains internal utilities used for testing the library.
/// While technically public, the library's users are not supposed to rely
/// on this module, as it will change without notice.
//
// Integration tests (i.e. everything under `tests/`) import this
// via `tests/test_utils/helpers`.
#[cfg(not(feature = "std"))]
use alloc::{
boxed::Box,
string::{String, ToString},
vec,
vec::Vec,
};
use core::fmt::Debug;
use crate::dialect::*;
use crate::parser::{Parser, ParserError};
use crate::tokenizer::{Token, Tokenizer};
use crate::{ast::*, parser::ParserOptions};
#[cfg(test)]
use pretty_assertions::assert_eq;
/// Tests use the methods on this struct to invoke the parser on one or
/// multiple dialects.
pub struct TestedDialects {
pub dialects: Vec<Box<dyn Dialect>>,
pub options: Option<ParserOptions>,
pub recursion_limit: Option<usize>,
}
impl TestedDialects {
/// Create a TestedDialects with default options and the given dialects.
pub fn new(dialects: Vec<Box<dyn Dialect>>) -> Self {
Self {
dialects,
options: None,
recursion_limit: None,
}
}
pub fn new_with_options(dialects: Vec<Box<dyn Dialect>>, options: ParserOptions) -> Self {
Self {
dialects,
options: Some(options),
recursion_limit: None,
}
}
pub fn with_recursion_limit(mut self, recursion_limit: usize) -> Self {
self.recursion_limit = Some(recursion_limit);
self
}
fn new_parser<'a>(&self, dialect: &'a dyn Dialect) -> Parser<'a> {
let parser = Parser::new(dialect);
let parser = if let Some(options) = &self.options {
parser.with_options(options.clone())
} else {
parser
};
let parser = if let Some(recursion_limit) = &self.recursion_limit {
parser.with_recursion_limit(*recursion_limit)
} else {
parser
};
parser
}
/// Run the given function for all of `self.dialects`, assert that they
/// return the same result, and return that result.
pub fn one_of_identical_results<F, T: Debug + PartialEq>(&self, f: F) -> T
where
F: Fn(&dyn Dialect) -> T,
{
let parse_results = self.dialects.iter().map(|dialect| (dialect, f(&**dialect)));
parse_results
.fold(None, |s, (dialect, parsed)| {
if let Some((prev_dialect, prev_parsed)) = s {
assert_eq!(
prev_parsed, parsed,
"Parse results with {prev_dialect:?} are different from {dialect:?}"
);
}
Some((dialect, parsed))
})
.expect("tested dialects cannot be empty")
.1
}
pub fn run_parser_method<F, T: Debug + PartialEq>(&self, sql: &str, f: F) -> T
where
F: Fn(&mut Parser) -> T,
{
self.one_of_identical_results(|dialect| {
let mut parser = self.new_parser(dialect).try_with_sql(sql).unwrap();
f(&mut parser)
})
}
/// Parses a single SQL string into multiple statements, ensuring
/// the result is the same for all tested dialects.
pub fn parse_sql_statements(&self, sql: &str) -> Result<Vec<Statement>, ParserError> {
self.one_of_identical_results(|dialect| {
let mut tokenizer = Tokenizer::new(dialect, sql);
if let Some(options) = &self.options {
tokenizer = tokenizer.with_unescape(options.unescape);
}
let tokens = tokenizer.tokenize()?;
self.new_parser(dialect)
.with_tokens(tokens)
.parse_statements()
})
// To fail the `ensure_multiple_dialects_are_tested` test:
// Parser::parse_sql(&**self.dialects.first().unwrap(), sql)
}
/// Ensures that `sql` parses as a single [Statement] for all tested
/// dialects.
///
/// In general, the canonical SQL should be the same (see crate
/// documentation for rationale) and you should prefer the `verified_`
/// variants in testing, such as [`verified_statement`] or
/// [`verified_query`].
///
/// If `canonical` is non empty,this function additionally asserts
/// that:
///
/// 1. parsing `sql` results in the same [`Statement`] as parsing
/// `canonical`.
///
/// 2. re-serializing the result of parsing `sql` produces the same
/// `canonical` sql string
///
/// For multiple statements, use [`statements_parse_to`].
pub fn one_statement_parses_to(&self, sql: &str, canonical: &str) -> Statement {
let mut statements = self.parse_sql_statements(sql).expect(sql);
assert_eq!(statements.len(), 1);
if !canonical.is_empty() && sql != canonical {
assert_eq!(self.parse_sql_statements(canonical).unwrap(), statements);
}
let only_statement = statements.pop().unwrap();
if !canonical.is_empty() {
assert_eq!(canonical, only_statement.to_string())
}
only_statement
}
/// The same as [`one_statement_parses_to`] but it works for a multiple statements
pub fn statements_parse_to(&self, sql: &str, canonical: &str) -> Vec<Statement> {
let statements = self.parse_sql_statements(sql).expect(sql);
if !canonical.is_empty() && sql != canonical {
assert_eq!(self.parse_sql_statements(canonical).unwrap(), statements);
} else {
assert_eq!(
sql,
statements
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join("; ")
);
}
statements
}
/// Ensures that `sql` parses as an [`Expr`], and that
/// re-serializing the parse result produces canonical
pub fn expr_parses_to(&self, sql: &str, canonical: &str) -> Expr {
let ast = self
.run_parser_method(sql, |parser| parser.parse_expr())
.unwrap();
assert_eq!(canonical, &ast.to_string());
ast
}
/// Ensures that `sql` parses as a single [Statement], and that
/// re-serializing the parse result produces the same `sql`
/// string (is not modified after a serialization round-trip).
pub fn verified_stmt(&self, sql: &str) -> Statement {
self.one_statement_parses_to(sql, sql)
}
/// Ensures that `sql` parses as a single [Query], and that
/// re-serializing the parse result produces the same `sql`
/// string (is not modified after a serialization round-trip).
pub fn verified_query(&self, sql: &str) -> Query {
match self.verified_stmt(sql) {
Statement::Query(query) => *query,
_ => panic!("Expected Query"),
}
}
/// Ensures that `sql` parses as a single [Query], and that
/// re-serializing the parse result matches the given canonical
/// sql string.
pub fn verified_query_with_canonical(&self, query: &str, canonical: &str) -> Query {
match self.one_statement_parses_to(query, canonical) {
Statement::Query(query) => *query,
_ => panic!("Expected Query"),
}
}
/// Ensures that `sql` parses as a single [Select], and that
/// re-serializing the parse result produces the same `sql`
/// string (is not modified after a serialization round-trip).
pub fn verified_only_select(&self, query: &str) -> Select {
match *self.verified_query(query).body {
SetExpr::Select(s) => *s,
_ => panic!("Expected SetExpr::Select"),
}
}
/// Ensures that `sql` parses as a single [`Select`], and that additionally:
///
/// 1. parsing `sql` results in the same [`Statement`] as parsing
/// `canonical`.
///
/// 2. re-serializing the result of parsing `sql` produces the same
/// `canonical` sql string
pub fn verified_only_select_with_canonical(&self, query: &str, canonical: &str) -> Select {
let q = match self.one_statement_parses_to(query, canonical) {
Statement::Query(query) => *query,
_ => panic!("Expected Query"),
};
match *q.body {
SetExpr::Select(s) => *s,
_ => panic!("Expected SetExpr::Select"),
}
}
/// Ensures that `sql` parses as an [`Expr`], and that
/// re-serializing the parse result produces the same `sql`
/// string (is not modified after a serialization round-trip).
pub fn verified_expr(&self, sql: &str) -> Expr {
self.expr_parses_to(sql, sql)
}
/// Check that the tokenizer returns the expected tokens for the given SQL.
pub fn tokenizes_to(&self, sql: &str, expected: Vec<Token>) {
if self.dialects.is_empty() {
panic!("No dialects to test");
}
self.dialects.iter().for_each(|dialect| {
let mut tokenizer = Tokenizer::new(&**dialect, sql);
if let Some(options) = &self.options {
tokenizer = tokenizer.with_unescape(options.unescape);
}
let tokens = tokenizer.tokenize().unwrap();
assert_eq!(expected, tokens, "Tokenized differently for {dialect:?}");
});
}
}
/// Returns all available dialects.
pub fn all_dialects() -> TestedDialects {
TestedDialects::new(vec![
Box::new(GenericDialect {}),
Box::new(PostgreSqlDialect {}),
Box::new(MsSqlDialect {}),
Box::new(AnsiDialect {}),
Box::new(SnowflakeDialect {}),
Box::new(HiveDialect {}),
Box::new(RedshiftSqlDialect {}),
Box::new(MySqlDialect {}),
Box::new(BigQueryDialect {}),
Box::new(SQLiteDialect {}),
Box::new(DuckDbDialect {}),
Box::new(DatabricksDialect {}),
Box::new(ClickHouseDialect {}),
])
}
/// Returns all dialects matching the given predicate.
pub fn all_dialects_where<F>(predicate: F) -> TestedDialects
where
F: Fn(&dyn Dialect) -> bool,
{
let mut dialects = all_dialects();
dialects.dialects.retain(|d| predicate(&**d));
dialects
}
/// Returns available dialects. The `except` predicate is used
/// to filter out specific dialects.
pub fn all_dialects_except<F>(except: F) -> TestedDialects
where
F: Fn(&dyn Dialect) -> bool,
{
all_dialects_where(|d| !except(d))
}
pub fn assert_eq_vec<T: ToString>(expected: &[&str], actual: &[T]) {
assert_eq!(
expected,
actual.iter().map(ToString::to_string).collect::<Vec<_>>()
);
}
pub fn only<T>(v: impl IntoIterator<Item = T>) -> T {
let mut iter = v.into_iter();
if let (Some(item), None) = (iter.next(), iter.next()) {
item
} else {
panic!("only called on collection without exactly one item")
}
}
pub fn expr_from_projection(item: &SelectItem) -> &Expr {
match item {
SelectItem::UnnamedExpr(expr) => expr,
_ => panic!("Expected UnnamedExpr"),
}
}
pub fn alter_table_op_with_name(stmt: Statement, expected_name: &str) -> AlterTableOperation {
match stmt {
Statement::AlterTable {
name,
if_exists,
only: is_only,
operations,
on_cluster: _,
location: _,
iceberg,
} => {
assert_eq!(name.to_string(), expected_name);
assert!(!if_exists);
assert!(!is_only);
assert!(!iceberg);
only(operations)
}
_ => panic!("Expected ALTER TABLE statement"),
}
}
pub fn alter_table_op(stmt: Statement) -> AlterTableOperation {
alter_table_op_with_name(stmt, "tab")
}
/// Creates a `Value::Number`, panic'ing if n is not a number
pub fn number(n: &str) -> Value {
Value::Number(n.parse().unwrap(), false)
}
/// Creates a [Value::SingleQuotedString]
pub fn single_quoted_string(s: impl Into<String>) -> Value {
Value::SingleQuotedString(s.into())
}
pub fn table_alias(name: impl Into<String>) -> Option<TableAlias> {
Some(TableAlias {
name: Ident::new(name),
columns: vec![],
})
}
pub fn table(name: impl Into<String>) -> TableFactor {
TableFactor::Table {
name: ObjectName::from(vec![Ident::new(name.into())]),
alias: None,
args: None,
with_hints: vec![],
version: None,
partitions: vec![],
with_ordinality: false,
json_path: None,
sample: None,
index_hints: vec![],
}
}
pub fn table_from_name(name: ObjectName) -> TableFactor {
TableFactor::Table {
name,
alias: None,
args: None,
with_hints: vec![],
version: None,
partitions: vec![],
with_ordinality: false,
json_path: None,
sample: None,
index_hints: vec![],
}
}
pub fn table_with_alias(name: impl Into<String>, alias: impl Into<String>) -> TableFactor {
TableFactor::Table {
name: ObjectName::from(vec![Ident::new(name)]),
alias: Some(TableAlias {
name: Ident::new(alias),
columns: vec![],
}),
args: None,
with_hints: vec![],
version: None,
partitions: vec![],
with_ordinality: false,
json_path: None,
sample: None,
index_hints: vec![],
}
}
pub fn join(relation: TableFactor) -> Join {
Join {
relation,
global: false,
join_operator: JoinOperator::Join(JoinConstraint::Natural),
}
}
pub fn call(function: &str, args: impl IntoIterator<Item = Expr>) -> Expr {
Expr::Function(Function {
name: ObjectName::from(vec![Ident::new(function)]),
uses_odbc_syntax: false,
parameters: FunctionArguments::None,
args: FunctionArguments::List(FunctionArgumentList {
duplicate_treatment: None,
args: args
.into_iter()
.map(|arg| FunctionArg::Unnamed(FunctionArgExpr::Expr(arg)))
.collect(),
clauses: vec![],
}),
filter: None,
null_treatment: None,
over: None,
within_group: vec![],
})
}
/// Gets the first index column (mysql calls it a key part) of the first index found in a
/// [`Statement::CreateIndex`], [`Statement::CreateTable`], or [`Statement::AlterTable`].
pub fn index_column(stmt: Statement) -> Expr {
match stmt {
Statement::CreateIndex(CreateIndex { columns, .. }) => {
columns.first().unwrap().column.expr.clone()
}
Statement::CreateTable(CreateTable { constraints, .. }) => {
match constraints.first().unwrap() {
TableConstraint::Index { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::Unique { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::PrimaryKey { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::FulltextOrSpatial { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
}
}
Statement::AlterTable { operations, .. } => match operations.first().unwrap() {
AlterTableOperation::AddConstraint { constraint, .. } => {
match constraint {
TableConstraint::Index { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::Unique { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::PrimaryKey { columns, .. } => {
columns.first().unwrap().column.expr.clone()
}
TableConstraint::FulltextOrSpatial {
columns,
..
} => columns.first().unwrap().column.expr.clone(),
_ => panic!("Expected an index, unique, primary, full text, or spatial constraint (foreign key does not support general key part expressions)"),
}
}
_ => panic!("Expected a constraint"),
},
_ => panic!("Expected CREATE INDEX, ALTER TABLE, or CREATE TABLE, got: {stmt:?}"),
}
}

4073
src/tokenizer.rs Normal file

File diff suppressed because it is too large Load diff

414
tests/pretty_print.rs Normal file
View file

@ -0,0 +1,414 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
fn prettify(sql: &str) -> String {
let ast = Parser::parse_sql(&GenericDialect {}, sql).unwrap();
format!("{:#}", ast[0])
}
#[test]
fn test_pretty_print_select() {
assert_eq!(
prettify("SELECT a, b, c FROM my_table WHERE x = 1 AND y = 2"),
r#"
SELECT
a,
b,
c
FROM
my_table
WHERE
x = 1 AND y = 2
"#
.trim()
);
}
#[test]
fn test_pretty_print_join() {
assert_eq!(
prettify("SELECT a FROM table1 JOIN table2 ON table1.id = table2.id"),
r#"
SELECT
a
FROM
table1
JOIN table2 ON table1.id = table2.id
"#
.trim()
);
}
#[test]
fn test_pretty_print_subquery() {
assert_eq!(
prettify("SELECT * FROM (SELECT a, b FROM my_table) AS subquery"),
r#"
SELECT
*
FROM
(
SELECT
a,
b
FROM
my_table
) AS subquery
"#
.trim()
);
}
#[test]
fn test_pretty_print_union() {
assert_eq!(
prettify("SELECT a FROM table1 UNION SELECT b FROM table2"),
r#"
SELECT
a
FROM
table1
UNION
SELECT
b
FROM
table2
"#
.trim()
);
}
#[test]
fn test_pretty_print_group_by() {
assert_eq!(
prettify("SELECT a, COUNT(*) FROM my_table GROUP BY a HAVING COUNT(*) > 1"),
r#"
SELECT
a,
COUNT(*)
FROM
my_table
GROUP BY
a
HAVING
COUNT(*) > 1
"#
.trim()
);
}
#[test]
fn test_pretty_print_cte() {
assert_eq!(
prettify("WITH cte AS (SELECT a, b FROM my_table) SELECT * FROM cte"),
r#"
WITH cte AS (
SELECT
a,
b
FROM
my_table
)
SELECT
*
FROM
cte
"#
.trim()
);
}
#[test]
fn test_pretty_print_case_when() {
assert_eq!(
prettify("SELECT CASE WHEN x > 0 THEN 'positive' WHEN x < 0 THEN 'negative' ELSE 'zero' END FROM my_table"),
r#"
SELECT
CASE
WHEN x > 0 THEN
'positive'
WHEN x < 0 THEN
'negative'
ELSE
'zero'
END
FROM
my_table
"#.trim()
);
}
#[test]
fn test_pretty_print_window_function() {
assert_eq!(
prettify("SELECT id, value, ROW_NUMBER() OVER (PARTITION BY category ORDER BY value DESC) as rank FROM my_table"),
r#"
SELECT
id,
value,
ROW_NUMBER() OVER (
PARTITION BY category
ORDER BY value DESC
) AS rank
FROM
my_table
"#.trim()
);
}
#[test]
fn test_pretty_print_multiline_string() {
assert_eq!(
prettify("SELECT 'multiline\nstring' AS str"),
r#"
SELECT
'multiline
string' AS str
"#
.trim(),
"A literal string with a newline should be kept as is. The contents of the string should not be indented."
);
}
#[test]
fn test_pretty_print_insert_values() {
assert_eq!(
prettify("INSERT INTO my_table (a, b, c) VALUES (1, 2, 3), (4, 5, 6)"),
r#"
INSERT INTO my_table (a, b, c)
VALUES
(1, 2, 3),
(4, 5, 6)
"#
.trim()
);
}
#[test]
fn test_pretty_print_insert_select() {
assert_eq!(
prettify("INSERT INTO my_table (a, b) SELECT x, y FROM source_table RETURNING a AS id"),
r#"
INSERT INTO my_table (a, b)
SELECT
x,
y
FROM
source_table
RETURNING
a AS id
"#
.trim()
);
}
#[test]
fn test_pretty_print_update() {
assert_eq!(
prettify("UPDATE my_table SET a = 1, b = 2 WHERE x > 0 RETURNING id, name"),
r#"
UPDATE my_table
SET
a = 1,
b = 2
WHERE
x > 0
RETURNING
id,
name
"#
.trim()
);
}
#[test]
fn test_pretty_print_delete() {
assert_eq!(
prettify("DELETE FROM my_table WHERE x > 0 RETURNING id, name"),
r#"
DELETE FROM
my_table
WHERE
x > 0
RETURNING
id,
name
"#
.trim()
);
assert_eq!(
prettify("DELETE table1, table2"),
r#"
DELETE
table1,
table2
"#
.trim()
);
}
#[test]
fn test_pretty_print_create_table() {
assert_eq!(
prettify("CREATE TABLE my_table (id INT PRIMARY KEY, name VARCHAR(255) NOT NULL, CONSTRAINT fk_other FOREIGN KEY (id) REFERENCES other_table(id))"),
r#"
CREATE TABLE my_table (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
CONSTRAINT fk_other FOREIGN KEY (id) REFERENCES other_table(id)
)
"#
.trim()
);
}
#[test]
fn test_pretty_print_create_view() {
assert_eq!(
prettify("CREATE VIEW my_view AS SELECT a, b FROM my_table WHERE x > 0"),
r#"
CREATE VIEW my_view AS
SELECT
a,
b
FROM
my_table
WHERE
x > 0
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_create_function() {
assert_eq!(
prettify("CREATE FUNCTION my_func() RETURNS INT BEGIN SELECT COUNT(*) INTO @count FROM my_table; RETURN @count; END"),
r#"
CREATE FUNCTION my_func() RETURNS INT
BEGIN
SELECT COUNT(*) INTO @count FROM my_table;
RETURN @count;
END
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_json_table() {
assert_eq!(
prettify("SELECT * FROM JSON_TABLE(@json, '$[*]' COLUMNS (id INT PATH '$.id', name VARCHAR(255) PATH '$.name')) AS jt"),
r#"
SELECT
*
FROM
JSON_TABLE(
@json,
'$[*]' COLUMNS (
id INT PATH '$.id',
name VARCHAR(255) PATH '$.name'
)
) AS jt
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_transaction_blocks() {
assert_eq!(
prettify("BEGIN; UPDATE my_table SET x = 1; COMMIT;"),
r#"
BEGIN;
UPDATE my_table SET x = 1;
COMMIT;
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_control_flow() {
assert_eq!(
prettify("IF x > 0 THEN SELECT 'positive'; ELSE SELECT 'negative'; END IF;"),
r#"
IF x > 0 THEN
SELECT 'positive';
ELSE
SELECT 'negative';
END IF;
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_merge() {
assert_eq!(
prettify("MERGE INTO target_table t USING source_table s ON t.id = s.id WHEN MATCHED THEN UPDATE SET t.value = s.value WHEN NOT MATCHED THEN INSERT (id, value) VALUES (s.id, s.value)"),
r#"
MERGE INTO target_table t
USING source_table s ON t.id = s.id
WHEN MATCHED THEN
UPDATE SET t.value = s.value
WHEN NOT MATCHED THEN
INSERT (id, value) VALUES (s.id, s.value)
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_create_index() {
assert_eq!(
prettify("CREATE INDEX idx_name ON my_table (column1, column2)"),
r#"
CREATE INDEX idx_name
ON my_table (column1, column2)
"#
.trim()
);
}
#[test]
#[ignore = "https://github.com/apache/datafusion-sqlparser-rs/issues/1850"]
fn test_pretty_print_explain() {
assert_eq!(
prettify("EXPLAIN ANALYZE SELECT * FROM my_table WHERE x > 0"),
r#"
EXPLAIN ANALYZE
SELECT
*
FROM
my_table
WHERE
x > 0
"#
.trim()
);
}

39
tests/queries/tpch/1.sql Normal file
View file

@ -0,0 +1,39 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= date '1998-12-01' - interval '90' day (3)
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus;

51
tests/queries/tpch/10.sql Normal file
View file

@ -0,0 +1,51 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
c_custkey,
c_name,
sum(l_extendedprice * (1 - l_discount)) as revenue,
c_acctbal,
n_name,
c_address,
c_phone,
c_comment
from
customer,
orders,
lineitem,
nation
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate >= date '1993-10-01'
and o_orderdate < date '1993-10-01' + interval '3' month
and l_returnflag = 'R'
and c_nationkey = n_nationkey
group by
c_custkey,
c_name,
c_acctbal,
c_phone,
n_name,
c_address,
c_comment
order by
revenue desc;

47
tests/queries/tpch/11.sql Normal file
View file

@ -0,0 +1,47 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
ps_partkey,
sum(ps_supplycost * ps_availqty) as value
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'GERMANY'
group by
ps_partkey having
sum(ps_supplycost * ps_availqty) > (
select
sum(ps_supplycost * ps_availqty) * 0.0001000000
from
partsupp,
supplier,
nation
where
ps_suppkey = s_suppkey
and s_nationkey = n_nationkey
and n_name = 'GERMANY'
)
order by
value desc;

48
tests/queries/tpch/12.sql Normal file
View file

@ -0,0 +1,48 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
l_shipmode,
sum(case
when o_orderpriority = '1-URGENT'
or o_orderpriority = '2-HIGH'
then 1
else 0
end) as high_line_count,
sum(case
when o_orderpriority <> '1-URGENT'
and o_orderpriority <> '2-HIGH'
then 1
else 0
end) as low_line_count
from
orders,
lineitem
where
o_orderkey = l_orderkey
and l_shipmode in ('MAIL', 'SHIP')
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= date '1994-01-01'
and l_receiptdate < date '1994-01-01' + interval '1' year
group by
l_shipmode
order by
l_shipmode;

40
tests/queries/tpch/13.sql Normal file
View file

@ -0,0 +1,40 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
c_count,
count(*) as custdist
from
(
select
c_custkey,
count(o_orderkey)
from
customer left outer join orders on
c_custkey = o_custkey
and o_comment not like '%special%requests%'
group by
c_custkey
) as c_orders (c_custkey, c_count)
group by
c_count
order by
custdist desc,
c_count desc;

33
tests/queries/tpch/14.sql Normal file
View file

@ -0,0 +1,33 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
100.00 * sum(case
when p_type like 'PROMO%'
then l_extendedprice * (1 - l_discount)
else 0
end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue
from
lineitem,
part
where
l_partkey = p_partkey
and l_shipdate >= date '1995-09-01'
and l_shipdate < date '1995-09-01' + interval '1' month;

53
tests/queries/tpch/15.sql Normal file
View file

@ -0,0 +1,53 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= date '1996-01-01'
and l_shipdate < date '1996-01-01' + interval '3' month
group by
l_suppkey;
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey;
drop view revenue0;

50
tests/queries/tpch/16.sql Normal file
View file

@ -0,0 +1,50 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
p_brand,
p_type,
p_size,
count(distinct ps_suppkey) as supplier_cnt
from
partsupp,
part
where
p_partkey = ps_partkey
and p_brand <> 'Brand#45'
and p_type not like 'MEDIUM POLISHED%'
and p_size in (49, 14, 23, 45, 19, 3, 36, 9)
and ps_suppkey not in (
select
s_suppkey
from
supplier
where
s_comment like '%Customer%Complaints%'
)
group by
p_brand,
p_type,
p_size
order by
supplier_cnt desc,
p_brand,
p_type,
p_size;

37
tests/queries/tpch/17.sql Normal file
View file

@ -0,0 +1,37 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
sum(l_extendedprice) / 7.0 as avg_yearly
from
lineitem,
part
where
p_partkey = l_partkey
and p_brand = 'Brand#23'
and p_container = 'MED BOX'
and l_quantity < (
select
0.2 * avg(l_quantity)
from
lineitem
where
l_partkey = p_partkey
);

52
tests/queries/tpch/18.sql Normal file
View file

@ -0,0 +1,52 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
c_name,
c_custkey,
o_orderkey,
o_orderdate,
o_totalprice,
sum(l_quantity)
from
customer,
orders,
lineitem
where
o_orderkey in (
select
l_orderkey
from
lineitem
group by
l_orderkey having
sum(l_quantity) > 300
)
and c_custkey = o_custkey
and o_orderkey = l_orderkey
group by
c_name,
c_custkey,
o_orderkey,
o_orderdate,
o_totalprice
order by
o_totalprice desc,
o_orderdate;

55
tests/queries/tpch/19.sql Normal file
View file

@ -0,0 +1,55 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
sum(l_extendedprice* (1 - l_discount)) as revenue
from
lineitem,
part
where
(
p_partkey = l_partkey
and p_brand = 'Brand#12'
and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')
and l_quantity >= 1 and l_quantity <= 1 + 10
and p_size between 1 and 5
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#23'
and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')
and l_quantity >= 10 and l_quantity <= 10 + 10
and p_size between 1 and 10
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
)
or
(
p_partkey = l_partkey
and p_brand = 'Brand#34'
and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')
and l_quantity >= 20 and l_quantity <= 20 + 10
and p_size between 1 and 15
and l_shipmode in ('AIR', 'AIR REG')
and l_shipinstruct = 'DELIVER IN PERSON'
);

62
tests/queries/tpch/2.sql Normal file
View file

@ -0,0 +1,62 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.
-- using default substitutions
select
s_acctbal,
s_name,
n_name,
p_partkey,
p_mfgr,
s_address,
s_phone,
s_comment
from
part,
supplier,
partsupp,
nation,
region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and p_size = 15
and p_type like '%BRASS'
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'EUROPE'
and ps_supplycost = (
select
min(ps_supplycost)
from
partsupp,
supplier,
nation,
region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'EUROPE'
)
order by
s_acctbal desc,
n_name,
s_name,
p_partkey;

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