Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for parsing MsSql alias with equals #1467

Merged
merged 6 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,17 @@ pub trait Dialect: Debug + Any {
fn supports_asc_desc_in_column_definition(&self) -> bool {
false
}

/// Returns true if this dialect supports treating the equals operator `=` within a [`SelectItem`]
/// as an alias assignment operator, rather than a boolean expression.
/// For example: the following statements are equivalent for such a dialect:
/// ```sql
/// SELECT col_alias = col FROM tbl;
/// SELECT col_alias AS col FROM tbl;
/// ```
fn supports_eq_alias_assigment(&self) -> bool {
false
}
}

/// This represents the operators for which precedence must be defined
Expand Down
4 changes: 4 additions & 0 deletions src/dialect/mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ impl Dialect for MsSqlDialect {
fn supports_connect_by(&self) -> bool {
true
}

fn supports_eq_alias_assigment(&self) -> bool {
true
}
}
18 changes: 18 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11181,6 +11181,24 @@ impl<'a> Parser<'a> {
self.peek_token().location
)
}
Expr::BinaryOp {
left,
op: BinaryOperator::Eq,
right,
} if self.dialect.supports_eq_alias_assigment()
&& matches!(left.as_ref(), Expr::Identifier(_)) =>
{
let Expr::Identifier(alias) = *left else {
return parser_err!(
"BUG: expected identifier expression as alias",
self.peek_token().location
);
};
Ok(SelectItem::ExprWithAlias {
expr: *right,
alias,
})
}
expr => self
.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS)
.map(|alias| match alias {
Expand Down
12 changes: 12 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11432,3 +11432,15 @@ fn test_any_some_all_comparison() {
verified_stmt("SELECT c1 FROM tbl WHERE c1 <> SOME(SELECT c2 FROM tbl)");
verified_stmt("SELECT 1 = ANY(WITH x AS (SELECT 1) SELECT * FROM x)");
}

#[test]
fn test_alias_equal_expr() {
let dialects = all_dialects_where(|d| d.supports_eq_alias_assigment());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yoavcloud just one comment on the test from here if we can include a similar case for the other dialects verifying that the some_alias = some_column gets parsed as an actual expression vs an alias?

Beyond that I think this should be good to go, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, done!

let sql = r#"SELECT some_alias = some_column FROM some_table"#;
let expected = r#"SELECT some_column AS some_alias FROM some_table"#;
let _ = dialects.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 _ = dialects.one_statement_parses_to(sql, expected);
}