From 787d1a1cb4fdbb9a40a9fceb68958db6b1c0d27a Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Fri, 11 Oct 2024 08:47:11 +0200 Subject: [PATCH 1/2] Add support for parsing MsSql alias with equals --- src/parser/mod.rs | 39 +++++++++++++++++++++++++++++++++------ tests/sqlparser_mssql.rs | 11 +++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index cd9be1d8f..f62bd8d22 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -11173,15 +11173,42 @@ impl<'a> Parser<'a> { self.peek_token().location ) } - expr => self - .parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS) - .map(|alias| match alias { - Some(alias) => SelectItem::ExprWithAlias { expr, alias }, - None => SelectItem::UnnamedExpr(expr), - }), + expr => { + if dialect_of!(self is MsSqlDialect) { + if let Some(select_item) = self.parse_mssql_alias_with_equal(&expr) { + return Ok(select_item); + } + } + self.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS) + .map(|alias| match alias { + Some(alias) => SelectItem::ExprWithAlias { expr, alias }, + None => SelectItem::UnnamedExpr(expr), + }) + } } } + /// Parse a [`SelectItem`] based on an MsSql syntax that uses the equal sign + /// to denote an alias, for example: SELECT col_alias = col FROM tbl + /// + fn parse_mssql_alias_with_equal(&mut self, expr: &Expr) -> Option { + if let Expr::BinaryOp { + left, op, right, .. + } = expr + { + if op == &BinaryOperator::Eq { + if let Expr::Identifier(ref alias) = **left { + return Some(SelectItem::ExprWithAlias { + expr: *right.clone(), + alias: alias.clone(), + }); + } + } + } + + None + } + /// Parse an [`WildcardAdditionalOptions`] information for wildcard select items. /// /// If it is not possible to parse it, will return an option. diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 5a2ef9e87..7ebd6026a 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -1024,6 +1024,17 @@ fn parse_create_table_with_identity_column() { } } +#[test] +fn test_alias_equal_expr() { + let sql = r#"SELECT some_alias = some_column FROM some_table"#; + let expected = r#"SELECT some_column AS some_alias FROM some_table"#; + let _ = ms().one_statement_parses_to(sql, expected); + + let sql = r#"SELECT some_alias = (a*b) FROM some_table"#; + let expected = r#"SELECT (a * b) AS some_alias FROM some_table"#; + let _ = ms().one_statement_parses_to(sql, expected); +} + fn ms() -> TestedDialects { TestedDialects { dialects: vec![Box::new(MsSqlDialect {})], From cb7eeed2aa7b4fdeb402e0df6e56a8b662633efb Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Mon, 14 Oct 2024 08:02:32 +0200 Subject: [PATCH 2/2] Try to inline the function based on code review feedback --- src/dialect/mod.rs | 5 +++++ src/dialect/mssql.rs | 4 ++++ src/parser/mod.rs | 47 +++++++++++++++++++++----------------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 744f5a8c8..01cceac36 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -561,6 +561,11 @@ pub trait Dialect: Debug + Any { fn supports_asc_desc_in_column_definition(&self) -> bool { false } + + /// For example: SELECT col_alias = col FROM tbl + fn supports_eq_alias_assigment(&self) -> bool { + false + } } /// This represents the operators for which precedence must be defined diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs index a9d296be3..cace372c0 100644 --- a/src/dialect/mssql.rs +++ b/src/dialect/mssql.rs @@ -49,4 +49,8 @@ impl Dialect for MsSqlDialect { fn supports_connect_by(&self) -> bool { true } + + fn supports_eq_alias_assigment(&self) -> bool { + true + } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index f62bd8d22..138d30ca8 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -11174,11 +11174,29 @@ impl<'a> Parser<'a> { ) } expr => { - if dialect_of!(self is MsSqlDialect) { - if let Some(select_item) = self.parse_mssql_alias_with_equal(&expr) { - return Ok(select_item); + // Parse a [`SelectItem`] based on an [MsSql] syntax that uses the equal sign + // to denote an alias, for example: SELECT col_alias = col FROM tbl + // [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/queries/select-examples-transact-sql?view=sql-server-ver16#b-use-select-with-column-headings-and-calculations + let expr = if self.dialect.supports_eq_alias_assigment() { + if let Expr::BinaryOp { + ref left, + op: BinaryOperator::Eq, + ref right, + } = expr + { + if let Expr::Identifier(alias) = left.as_ref() { + return Ok(SelectItem::ExprWithAlias { + expr: *right.clone(), + alias: alias.clone(), + }); + } } - } + expr + } else { + expr + }; + + // Parse the common AS keyword for aliasing a column self.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS) .map(|alias| match alias { Some(alias) => SelectItem::ExprWithAlias { expr, alias }, @@ -11188,27 +11206,6 @@ impl<'a> Parser<'a> { } } - /// Parse a [`SelectItem`] based on an MsSql syntax that uses the equal sign - /// to denote an alias, for example: SELECT col_alias = col FROM tbl - /// - fn parse_mssql_alias_with_equal(&mut self, expr: &Expr) -> Option { - if let Expr::BinaryOp { - left, op, right, .. - } = expr - { - if op == &BinaryOperator::Eq { - if let Expr::Identifier(ref alias) = **left { - return Some(SelectItem::ExprWithAlias { - expr: *right.clone(), - alias: alias.clone(), - }); - } - } - } - - None - } - /// Parse an [`WildcardAdditionalOptions`] information for wildcard select items. /// /// If it is not possible to parse it, will return an option.