From b2ec1ea6eccbf8c0ad85fad228a290b702cdeb75 Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> Date: Thu, 1 Dec 2022 04:21:24 +0400 Subject: [PATCH 1/3] feat: Add `APPROXIMATE` function keyword support --- src/ast/mod.rs | 5 +++ src/keywords.rs | 1 + src/parser.rs | 14 +++++++ ..._clickhouse.rs => sqlparser_clickhouse.rs} | 2 + tests/sqlparser_common.rs | 18 +++++++++ tests/sqlparser_mysql.rs | 5 +++ tests/sqlparser_postgres.rs | 40 +++++++++++++++++++ 7 files changed, 85 insertions(+) rename tests/{sqpparser_clickhouse.rs => sqlparser_clickhouse.rs} (98%) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index f7b447950..05516815e 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2231,10 +2231,15 @@ pub struct Function { // aggregate functions may specify eg `COUNT(DISTINCT x)` pub distinct: bool, pub special: bool, + // Redshift provides `APPROXIMATE` option for some functions, e.g. `COUNT` + pub approximate: bool, } impl fmt::Display for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.approximate { + write!(f, "APPROXIMATE ")?; + } if self.special { write!(f, "{}", self.name)?; } else { diff --git a/src/keywords.rs b/src/keywords.rs index 06ab8731e..e61266b39 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -77,6 +77,7 @@ define_keywords!( AND, ANY, APPLY, + APPROXIMATE, ARE, ARRAY, ARRAY_AGG, diff --git a/src/parser.rs b/src/parser.rs index fbb7d747a..5788c5bd4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -330,6 +330,17 @@ impl<'a> Parser<'a> { } } } + Token::Word(w) + if dialect_of!(self is RedshiftSqlDialect | PostgreSqlDialect | GenericDialect) + && w.keyword == Keyword::APPROXIMATE + && self.peek_token() != Token::Comma => + { + let mut expr = self.parse_expr()?; + if let Expr::Function(fun) = &mut expr { + fun.approximate = true; + return Ok(WildcardExpr::Expr(expr)); + } + } Token::Mul => { return Ok(WildcardExpr::Wildcard); } @@ -433,6 +444,7 @@ impl<'a> Parser<'a> { over: None, distinct: false, special: true, + approximate: false, })) } Keyword::CURRENT_TIMESTAMP @@ -620,6 +632,7 @@ impl<'a> Parser<'a> { over, distinct, special: false, + approximate: false, })) } @@ -635,6 +648,7 @@ impl<'a> Parser<'a> { over: None, distinct: false, special: false, + approximate: false, })) } diff --git a/tests/sqpparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs similarity index 98% rename from tests/sqpparser_clickhouse.rs rename to tests/sqlparser_clickhouse.rs index 7e1ecaed8..583f8f8f9 100644 --- a/tests/sqpparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -52,6 +52,7 @@ fn parse_map_access_expr() { over: None, distinct: false, special: false, + approximate: false, })], })], into: None, @@ -88,6 +89,7 @@ fn parse_map_access_expr() { over: None, distinct: false, special: false, + approximate: false, })] }), op: BinaryOperator::NotEq, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 04b91a43d..ebc9e340a 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -511,6 +511,7 @@ fn parse_select_count_wildcard() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(only(&select.projection)) ); @@ -530,6 +531,7 @@ fn parse_select_count_distinct() { over: None, distinct: true, special: false, + approximate: false, }), expr_from_projection(only(&select.projection)) ); @@ -1335,6 +1337,7 @@ fn parse_select_having() { over: None, distinct: false, special: false, + approximate: false, })), op: BinaryOperator::Gt, right: Box::new(Expr::Value(number("1"))) @@ -2325,6 +2328,7 @@ fn parse_scalar_function_in_projection() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(only(&select.projection)) ); @@ -2404,6 +2408,7 @@ fn parse_named_argument_function() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(only(&select.projection)) ); @@ -2438,6 +2443,7 @@ fn parse_window_functions() { }), distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -2547,6 +2553,7 @@ fn parse_expr_interval() { over: None, distinct: false, special: false, + approximate: false, }); assert_eq!( @@ -2579,6 +2586,7 @@ fn parse_expr_interval() { over: None, distinct: false, special: false, + approximate: false, }); assert_eq!( &Expr::Value(Value::Interval { @@ -2724,6 +2732,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + approximate: false, })), time_zone: "UTC-06:00".to_string() }, @@ -2750,6 +2759,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + approximate: false, },)), time_zone: "UTC-06:00".to_string(), },),), @@ -2760,6 +2770,7 @@ fn parse_at_timezone() { over: None, distinct: false, special: false, + approximate: false, },), alias: Ident { value: "hour".to_string(), @@ -2796,6 +2807,7 @@ fn parse_table_function() { over: None, distinct: false, special: false, + approximate: false, }); assert_eq!(expr, expected_expr); assert_eq!(alias, table_alias("a")) @@ -2853,6 +2865,7 @@ fn parse_delimited_identifiers() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[1]), ); @@ -4763,6 +4776,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -4779,6 +4793,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -4795,6 +4810,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -4811,6 +4827,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -4827,6 +4844,7 @@ fn parse_time_functions() { over: None, distinct: false, special: false, + approximate: false, }), expr_from_projection(&select.projection[0]) ); diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 37952e780..c3204f156 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -694,6 +694,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + approximate: false, }) }, Assignment { @@ -706,6 +707,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + approximate: false, }) }, Assignment { @@ -718,6 +720,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + approximate: false, }) }, Assignment { @@ -730,6 +733,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + approximate: false, }) }, Assignment { @@ -742,6 +746,7 @@ fn parse_insert_with_on_duplicate_update() { over: None, distinct: false, special: false, + approximate: false, }) }, ])), diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index cd5e55492..c10dfef76 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1418,6 +1418,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + approximate: false, }), expr_from_projection(&select.projection[0]) ); @@ -1428,6 +1429,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + approximate: false, }), expr_from_projection(&select.projection[1]) ); @@ -1438,6 +1440,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + approximate: false, }), expr_from_projection(&select.projection[2]) ); @@ -1448,6 +1451,7 @@ fn parse_current_functions() { over: None, distinct: false, special: true, + approximate: false, }), expr_from_projection(&select.projection[3]) ); @@ -1571,3 +1575,39 @@ fn parse_pg_extract() { res.unwrap_err() ); } + +#[test] +fn parse_approximate_count() { + let sql = "SELECT APPROXIMATE COUNT(DISTINCT column)"; + let select = pg_and_generic().verified_only_select(sql); + assert_eq!( + &Expr::Function(Function { + name: ObjectName(vec!["COUNT".into()]), + args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr( + Expr::Identifier(Ident::new("column")) + )),], + over: None, + distinct: true, + special: false, + approximate: true, + }), + expr_from_projection(only(&select.projection)), + ); + + let sql = "SELECT APPROXIMATE AS alias"; + let select = pg_and_generic().verified_only_select(sql); + assert_eq!( + SelectItem::ExprWithAlias { + expr: Expr::Identifier(Ident::new("APPROXIMATE")), + alias: Ident::new("alias"), + }, + select.projection[0] + ); + + let sql = "SELECT APPROXIMATE, COUNT(DISTINCT column)"; + let select = pg_and_generic().verified_only_select(sql); + assert_eq!( + SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("APPROXIMATE"))), + select.projection[0] + ); +} From c8467a6466d4fb0f912e36caf0c501d08bd27930 Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> Date: Thu, 1 Dec 2022 03:11:17 +0400 Subject: [PATCH 2/3] ci: Lock Rust toolchain --- .github/workflows/rust.yml | 10 +++++----- rust-toolchain | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 07bb67bef..bd3d8ba72 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,11 +11,9 @@ jobs: uses: hecrj/setup-rust-action@v1 with: components: rustfmt - # Note that `nightly` is required for `license_template_path`, as - # it's an unstable feature. - rust-version: nightly + rust-version: nightly-2022-03-08 - uses: actions/checkout@v2 - - run: cargo +nightly fmt -- --check --config-path <(echo 'license_template_path = "HEADER"') + - run: cargo fmt -- --check --config-path <(echo 'license_template_path = "HEADER"') lint: runs-on: ubuntu-latest @@ -24,6 +22,7 @@ jobs: uses: hecrj/setup-rust-action@v1 with: components: clippy + rust-version: nightly-2022-03-08 - uses: actions/checkout@v2 - run: cargo clippy --all-targets --all-features -- -D warnings @@ -42,13 +41,14 @@ jobs: uses: hecrj/setup-rust-action@v1 with: targets: 'thumbv6m-none-eabi' + rust-version: nightly-2022-03-08 - uses: actions/checkout@master - run: cargo check --no-default-features --target thumbv6m-none-eabi test: strategy: matrix: - rust: [stable, beta, nightly] + rust: [stable, beta, nightly, nightly-2022-03-08] runs-on: ubuntu-latest steps: - name: Setup Rust diff --git a/rust-toolchain b/rust-toolchain index 870bbe4e5..f367a50f0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -stable \ No newline at end of file +nightly-2022-03-08 From b7407b99320fc4fc6fe17242ae7c4116bc97e47a Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> Date: Thu, 1 Dec 2022 03:14:24 +0400 Subject: [PATCH 3/3] chore: Lock dependencies versions --- .gitignore | 4 - Cargo.lock | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 314 insertions(+), 4 deletions(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 6dfd81a68..ceff7cbfa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,6 @@ /target/ /sqlparser_bench/target/ -# 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 -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..9a0581ba7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,314 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bigdecimal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "ctor" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "simple_logger" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "166fea527c36d9b8a0a88c0c6d4c5077c699d9ffb5cf890b231a3f08c35f3d40" +dependencies = [ + "atty", + "colored", + "log", + "time", + "winapi", +] + +[[package]] +name = "sqlparser" +version = "0.16.0" +dependencies = [ + "bigdecimal", + "log", + "matches", + "pretty_assertions", + "serde", + "serde_json", + "simple_logger", +] + +[[package]] +name = "syn" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"