From 62b7a97b1c1f23e02f6610b53fa069925ea6ae15 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sat, 26 Oct 2024 14:03:53 +0200 Subject: [PATCH 1/4] Add support for dialects (Redshift) that expect the TOP keyword in a SELECT statement to appear before the ALL/DISTINCT option --- src/ast/query.rs | 13 ++++++++++++- src/dialect/mod.rs | 6 ++++++ src/dialect/redshift.rs | 6 ++++++ src/keywords.rs | 1 + src/parser/mod.rs | 30 +++++++++++++++++++++--------- tests/sqlparser_mysql.rs | 8 ++++++++ tests/sqlparser_redshift.rs | 9 +++++++++ 7 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index dc5966e5e..57efe2910 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -327,12 +327,20 @@ impl fmt::Display for Select { write!(f, " {value_table_mode}")?; } + if let Some(ref top) = self.top { + if top.is_before_distinct { + write!(f, " {top}")?; + } + } if let Some(ref distinct) = self.distinct { write!(f, " {distinct}")?; } if let Some(ref top) = self.top { - write!(f, " {top}")?; + if !top.is_before_distinct { + write!(f, " {top}")?; + } } + write!(f, " {}", display_comma_separated(&self.projection))?; if let Some(ref into) = self.into { @@ -1996,6 +2004,9 @@ pub struct Top { /// MSSQL only. pub percent: bool, pub quantity: Option, + // Whether this option was parsed before `ALL`/`DISTINCT` + // See `Dialect::expects_top_before_distinct` + pub is_before_distinct: bool, } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 5abddba38..e4fc049f7 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -600,6 +600,12 @@ pub trait Dialect: Debug + Any { fn supports_notify(&self) -> bool { false } + + /// Returns true if this dialect expects the the `TOP` option + /// before the `ALL`/`DISTINCT` options + fn expects_top_before_distinct(&self) -> bool { + false + } } /// This represents the operators for which precedence must be defined diff --git a/src/dialect/redshift.rs b/src/dialect/redshift.rs index 3bfdec3b0..e425c78b2 100644 --- a/src/dialect/redshift.rs +++ b/src/dialect/redshift.rs @@ -68,4 +68,10 @@ impl Dialect for RedshiftSqlDialect { fn supports_connect_by(&self) -> bool { true } + + /// Redshift expects the `TOP` option before the `ALL/DISTINCT` option: + /// + fn expects_top_before_distinct(&self) -> bool { + true + } } diff --git a/src/keywords.rs b/src/keywords.rs index d60227c99..cbad6153c 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -255,6 +255,7 @@ define_keywords!( DISCARD, DISCONNECT, DISTINCT, + DISTINCTROW, DISTRIBUTE, DIV, DO, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index fd7d1c578..bea31ec56 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3553,7 +3553,9 @@ impl<'a> Parser<'a> { pub fn parse_all_or_distinct(&mut self) -> Result, ParserError> { let loc = self.peek_token().location; let all = self.parse_keyword(Keyword::ALL); - let distinct = self.parse_keyword(Keyword::DISTINCT); + let distinct = self + .parse_one_of_keywords(&[Keyword::DISTINCT, Keyword::DISTINCTROW]) + .is_some(); if !distinct { return Ok(None); } @@ -9193,12 +9195,14 @@ impl<'a> Parser<'a> { None }; - let distinct = self.parse_all_or_distinct()?; - - let top = if self.parse_keyword(Keyword::TOP) { - Some(self.parse_top()?) + let (distinct, top) = if self.dialect.expects_top_before_distinct() { + let top = self.maybe_parse_top(true)?; + let distinct = self.parse_all_or_distinct()?; + (distinct, top) } else { - None + let distinct = self.parse_all_or_distinct()?; + let top = self.maybe_parse_top(false)?; + (distinct, top) }; let projection = self.parse_projection()?; @@ -11552,7 +11556,14 @@ impl<'a> Parser<'a> { /// Parse a TOP clause, MSSQL equivalent of LIMIT, /// that follows after `SELECT [DISTINCT]`. - pub fn parse_top(&mut self) -> Result { + pub fn maybe_parse_top( + &mut self, + is_before_distinct: bool, + ) -> Result, ParserError> { + if !self.parse_keyword(Keyword::TOP) { + return Ok(None); + } + let quantity = if self.consume_token(&Token::LParen) { let quantity = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -11570,11 +11581,12 @@ impl<'a> Parser<'a> { let with_ties = self.parse_keywords(&[Keyword::WITH, Keyword::TIES]); - Ok(Top { + Ok(Some(Top { with_ties, percent, quantity, - }) + is_before_distinct, + })) } /// Parse a LIMIT clause diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 4b9354e85..92186c7ec 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -2803,3 +2803,11 @@ fn test_group_concat() { mysql_and_generic() .verified_expr("GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ')"); } + +#[test] +fn parse_select_distinctrow() { + mysql().one_statement_parses_to( + "SELECT DISTINCTROW a FROM tbl", + "SELECT DISTINCT a FROM tbl" + ); +} \ No newline at end of file diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index a25d50605..002ca2e07 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -196,3 +196,12 @@ fn test_create_view_with_no_schema_binding() { redshift_and_generic() .verified_stmt("CREATE VIEW myevent AS SELECT eventname FROM event WITH NO SCHEMA BINDING"); } + +#[test] +fn test_select_top() { + redshift().one_statement_parses_to("SELECT ALL * FROM tbl", "SELECT * FROM tbl"); + redshift().verified_stmt("SELECT TOP 3 * FROM tbl"); + redshift().one_statement_parses_to("SELECT TOP 3 ALL * FROM tbl", "SELECT TOP 3 * FROM tbl"); + redshift().verified_stmt("SELECT TOP 3 DISTINCT * FROM tbl"); + redshift().verified_stmt("SELECT TOP 3 DISTINCT a, b, c FROM tbl"); +} From 92f3f5352c4ba8c1c99c65a019940d40a5f8bc8c Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Thu, 31 Oct 2024 23:49:46 +0100 Subject: [PATCH 2/4] format --- tests/sqlparser_mysql.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 92186c7ec..71f87fbfc 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -2807,7 +2807,7 @@ fn test_group_concat() { #[test] fn parse_select_distinctrow() { mysql().one_statement_parses_to( - "SELECT DISTINCTROW a FROM tbl", - "SELECT DISTINCT a FROM tbl" + "SELECT DISTINCTROW a FROM tbl", + "SELECT DISTINCT a FROM tbl", ); -} \ No newline at end of file +} From 19c06a236273fd7facce7f287429a0e91ab4f609 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sun, 3 Nov 2024 08:06:42 +0100 Subject: [PATCH 3/4] Code review comments --- src/ast/query.rs | 9 ++++----- src/dialect/mod.rs | 4 ++-- src/dialect/redshift.rs | 2 +- src/parser/mod.rs | 34 ++++++++++++++-------------------- tests/sqlparser_clickhouse.rs | 1 + tests/sqlparser_common.rs | 18 ++++++++++++++++++ tests/sqlparser_duckdb.rs | 2 ++ tests/sqlparser_mssql.rs | 2 ++ tests/sqlparser_mysql.rs | 8 ++++++++ tests/sqlparser_postgres.rs | 3 +++ tests/sqlparser_redshift.rs | 9 --------- 11 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/ast/query.rs b/src/ast/query.rs index 57efe2910..6767662d5 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -279,6 +279,8 @@ pub struct Select { pub distinct: Option, /// MSSQL syntax: `TOP () [ PERCENT ] [ WITH TIES ]` pub top: Option, + /// Whether the top was located before `ALL`/`DISTINCT` + pub top_before_distinct: bool, /// projection expressions pub projection: Vec, /// INTO @@ -328,7 +330,7 @@ impl fmt::Display for Select { } if let Some(ref top) = self.top { - if top.is_before_distinct { + if self.top_before_distinct { write!(f, " {top}")?; } } @@ -336,7 +338,7 @@ impl fmt::Display for Select { write!(f, " {distinct}")?; } if let Some(ref top) = self.top { - if !top.is_before_distinct { + if !self.top_before_distinct { write!(f, " {top}")?; } } @@ -2004,9 +2006,6 @@ pub struct Top { /// MSSQL only. pub percent: bool, pub quantity: Option, - // Whether this option was parsed before `ALL`/`DISTINCT` - // See `Dialect::expects_top_before_distinct` - pub is_before_distinct: bool, } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index e4fc049f7..453fee3de 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -602,8 +602,8 @@ pub trait Dialect: Debug + Any { } /// Returns true if this dialect expects the the `TOP` option - /// before the `ALL`/`DISTINCT` options - fn expects_top_before_distinct(&self) -> bool { + /// before the `ALL`/`DISTINCT` options in a `SELECT` statement. + fn supports_top_before_distinct(&self) -> bool { false } } diff --git a/src/dialect/redshift.rs b/src/dialect/redshift.rs index e425c78b2..4d0773843 100644 --- a/src/dialect/redshift.rs +++ b/src/dialect/redshift.rs @@ -71,7 +71,7 @@ impl Dialect for RedshiftSqlDialect { /// Redshift expects the `TOP` option before the `ALL/DISTINCT` option: /// - fn expects_top_before_distinct(&self) -> bool { + fn supports_top_before_distinct(&self) -> bool { true } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index bea31ec56..0c9c2061a 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9195,15 +9195,16 @@ impl<'a> Parser<'a> { None }; - let (distinct, top) = if self.dialect.expects_top_before_distinct() { - let top = self.maybe_parse_top(true)?; - let distinct = self.parse_all_or_distinct()?; - (distinct, top) - } else { - let distinct = self.parse_all_or_distinct()?; - let top = self.maybe_parse_top(false)?; - (distinct, top) - }; + let mut top_before_distinct = false; + let mut top = None; + if self.dialect.supports_top_before_distinct() && self.parse_keyword(Keyword::TOP) { + top = Some(self.parse_top()?); + top_before_distinct = true; + } + let distinct = self.parse_all_or_distinct()?; + if !self.dialect.supports_top_before_distinct() && self.parse_keyword(Keyword::TOP) { + top = Some(self.parse_top()?); + } let projection = self.parse_projection()?; @@ -9346,6 +9347,7 @@ impl<'a> Parser<'a> { Ok(Select { distinct, top, + top_before_distinct, projection, into, from, @@ -11556,14 +11558,7 @@ impl<'a> Parser<'a> { /// Parse a TOP clause, MSSQL equivalent of LIMIT, /// that follows after `SELECT [DISTINCT]`. - pub fn maybe_parse_top( - &mut self, - is_before_distinct: bool, - ) -> Result, ParserError> { - if !self.parse_keyword(Keyword::TOP) { - return Ok(None); - } - + pub fn parse_top(&mut self) -> Result { let quantity = if self.consume_token(&Token::LParen) { let quantity = self.parse_expr()?; self.expect_token(&Token::RParen)?; @@ -11581,12 +11576,11 @@ impl<'a> Parser<'a> { let with_ties = self.parse_keywords(&[Keyword::WITH, Keyword::TIES]); - Ok(Some(Top { + Ok(Top { with_ties, percent, quantity, - is_before_distinct, - })) + }) } /// Parse a LIMIT clause diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs index f8c349a37..a71871115 100644 --- a/tests/sqlparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -40,6 +40,7 @@ fn parse_map_access_expr() { Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![UnnamedExpr(MapAccess { column: Box::new(Identifier(Ident { value: "string_values".to_string(), diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 334dae2b3..49753a1f4 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -379,6 +379,7 @@ fn parse_update_set_from() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("name"))), SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("id"))), @@ -4649,6 +4650,7 @@ fn test_parse_named_window() { let expected = Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::ExprWithAlias { expr: Expr::Function(Function { @@ -5289,6 +5291,7 @@ fn parse_interval_and_or_xor() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![UnnamedExpr(Expr::Identifier(Ident { value: "col".to_string(), quote_style: None, @@ -7367,6 +7370,7 @@ fn lateral_function() { let expected = Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { opt_ilike: None, opt_exclude: None, @@ -8215,6 +8219,7 @@ fn parse_merge() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::Wildcard( WildcardAdditionalOptions::default() )], @@ -9803,6 +9808,7 @@ fn parse_unload() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![UnnamedExpr(Expr::Identifier(Ident::new("cola"))),], into: None, from: vec![TableWithJoins { @@ -9978,6 +9984,7 @@ fn parse_connect_by() { let expect_query = Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("employee_id"))), SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("manager_id"))), @@ -10064,6 +10071,7 @@ fn parse_connect_by() { Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("employee_id"))), SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("manager_id"))), @@ -11475,3 +11483,13 @@ fn parse_notify_channel() { ); } } + +#[test] +fn test_select_top() { + let dialects = all_dialects_where(|d| d.supports_top_before_distinct()); + dialects.one_statement_parses_to("SELECT ALL * FROM tbl", "SELECT * FROM tbl"); + dialects.verified_stmt("SELECT TOP 3 * FROM tbl"); + dialects.one_statement_parses_to("SELECT TOP 3 ALL * FROM tbl", "SELECT TOP 3 * FROM tbl"); + dialects.verified_stmt("SELECT TOP 3 DISTINCT * FROM tbl"); + dialects.verified_stmt("SELECT TOP 3 DISTINCT a, b, c FROM tbl"); +} diff --git a/tests/sqlparser_duckdb.rs b/tests/sqlparser_duckdb.rs index a4109b0a3..d68f37713 100644 --- a/tests/sqlparser_duckdb.rs +++ b/tests/sqlparser_duckdb.rs @@ -261,6 +261,7 @@ fn test_select_union_by_name() { left: Box::::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { opt_ilike: None, opt_exclude: None, @@ -301,6 +302,7 @@ fn test_select_union_by_name() { right: Box::::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::Wildcard(WildcardAdditionalOptions { opt_ilike: None, opt_exclude: None, diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 0223e2915..c5f43b072 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -114,6 +114,7 @@ fn parse_create_procedure() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Value(number("1")))], into: None, from: vec![], @@ -514,6 +515,7 @@ fn parse_substring_in_select() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: Some(Distinct::Distinct), top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Substring { expr: Box::new(Expr::Identifier(Ident { value: "description".to_string(), diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 71f87fbfc..50f6f0cd2 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -957,6 +957,7 @@ fn parse_escaped_quote_identifiers_with_escape() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "quoted ` identifier".into(), quote_style: Some('`'), @@ -1007,6 +1008,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "quoted `` identifier".into(), quote_style: Some('`'), @@ -1050,6 +1052,7 @@ fn parse_escaped_backticks_with_escape() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "`quoted identifier`".into(), quote_style: Some('`'), @@ -1097,6 +1100,7 @@ fn parse_escaped_backticks_with_no_escape() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident { value: "``quoted identifier``".into(), quote_style: Some('`'), @@ -1741,6 +1745,7 @@ fn parse_select_with_numeric_prefix_column_name() { Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident::new( "123col_$@123abc" )))], @@ -1795,6 +1800,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() { Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::UnnamedExpr(Expr::Value(number("123e4"))), SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("123col_$@123abc"))) @@ -2295,6 +2301,7 @@ fn parse_substring_in_select() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: Some(Distinct::Distinct), top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Substring { expr: Box::new(Expr::Identifier(Ident { value: "description".to_string(), @@ -2616,6 +2623,7 @@ fn parse_hex_string_introducer() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::IntroducedString { introducer: "_latin1".to_string(), value: Value::HexStringLiteral("4D7953514C".to_string()) diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index b9b3811ba..c30603baa 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1165,6 +1165,7 @@ fn parse_copy_to() { body: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![ SelectItem::ExprWithAlias { expr: Expr::Value(number("42")), @@ -2505,6 +2506,7 @@ fn parse_array_subquery_expr() { left: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Value(number("1")))], into: None, from: vec![], @@ -2525,6 +2527,7 @@ fn parse_array_subquery_expr() { right: Box::new(SetExpr::Select(Box::new(Select { distinct: None, top: None, + top_before_distinct: false, projection: vec![SelectItem::UnnamedExpr(Expr::Value(number("2")))], into: None, from: vec![], diff --git a/tests/sqlparser_redshift.rs b/tests/sqlparser_redshift.rs index 002ca2e07..a25d50605 100644 --- a/tests/sqlparser_redshift.rs +++ b/tests/sqlparser_redshift.rs @@ -196,12 +196,3 @@ fn test_create_view_with_no_schema_binding() { redshift_and_generic() .verified_stmt("CREATE VIEW myevent AS SELECT eventname FROM event WITH NO SCHEMA BINDING"); } - -#[test] -fn test_select_top() { - redshift().one_statement_parses_to("SELECT ALL * FROM tbl", "SELECT * FROM tbl"); - redshift().verified_stmt("SELECT TOP 3 * FROM tbl"); - redshift().one_statement_parses_to("SELECT TOP 3 ALL * FROM tbl", "SELECT TOP 3 * FROM tbl"); - redshift().verified_stmt("SELECT TOP 3 DISTINCT * FROM tbl"); - redshift().verified_stmt("SELECT TOP 3 DISTINCT a, b, c FROM tbl"); -} From 9eec5f3c4fa293475088ebf75a288cb491e704e4 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 6 Nov 2024 08:13:07 +0100 Subject: [PATCH 4/4] Remove distinctrow handling from this PR --- src/keywords.rs | 1 - src/parser/mod.rs | 4 +--- tests/sqlparser_mysql.rs | 8 -------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/keywords.rs b/src/keywords.rs index cbad6153c..d60227c99 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -255,7 +255,6 @@ define_keywords!( DISCARD, DISCONNECT, DISTINCT, - DISTINCTROW, DISTRIBUTE, DIV, DO, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0c9c2061a..de11ba7c9 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3553,9 +3553,7 @@ impl<'a> Parser<'a> { pub fn parse_all_or_distinct(&mut self) -> Result, ParserError> { let loc = self.peek_token().location; let all = self.parse_keyword(Keyword::ALL); - let distinct = self - .parse_one_of_keywords(&[Keyword::DISTINCT, Keyword::DISTINCTROW]) - .is_some(); + let distinct = self.parse_keyword(Keyword::DISTINCT); if !distinct { return Ok(None); } diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 50f6f0cd2..6cd08df18 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -2811,11 +2811,3 @@ fn test_group_concat() { mysql_and_generic() .verified_expr("GROUP_CONCAT(DISTINCT test_score ORDER BY test_score DESC SEPARATOR ' ')"); } - -#[test] -fn parse_select_distinctrow() { - mysql().one_statement_parses_to( - "SELECT DISTINCTROW a FROM tbl", - "SELECT DISTINCT a FROM tbl", - ); -}