Skip to content

Commit

Permalink
Add the QUALIFY keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
ggevay committed Jan 16, 2025
1 parent 6c64c4d commit ff6b73f
Show file tree
Hide file tree
Showing 24 changed files with 349 additions and 208 deletions.
2 changes: 1 addition & 1 deletion src/sql-lexer/src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Keyword {
matches!(
self,
// Keywords that can appear at the top-level of a SELECT statement.
WITH | SELECT | FROM | WHERE | GROUP | HAVING | ORDER | LIMIT | OFFSET | FETCH | OPTIONS | RETURNING |
WITH | SELECT | FROM | WHERE | GROUP | HAVING | QUALIFY | ORDER | LIMIT | OFFSET | FETCH | OPTIONS | RETURNING |
// Set operations.
UNION | EXCEPT | INTERSECT
)
Expand Down
1 change: 1 addition & 0 deletions src/sql-lexer/src/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ Protocol
Public
Publication
Pushdown
Qualify
Query
Quote
Raise
Expand Down
6 changes: 6 additions & 0 deletions src/sql-parser/src/ast/defs/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ pub struct Select<T: AstInfo> {
pub group_by: Vec<Expr<T>>,
/// HAVING
pub having: Option<Expr<T>>,
/// QUALIFY
pub qualify: Option<Expr<T>>,
/// OPTION
pub options: Vec<SelectOption<T>>,
}
Expand Down Expand Up @@ -275,6 +277,10 @@ impl<T: AstInfo> AstDisplay for Select<T> {
f.write_str(" HAVING ");
f.write_node(having);
}
if let Some(ref qualify) = self.qualify {
f.write_str(" QUALIFY ");
f.write_node(qualify);
}
if !self.options.is_empty() {
f.write_str(" OPTIONS (");
f.write_node(&display::comma_separated(&self.options));
Expand Down
8 changes: 8 additions & 0 deletions src/sql-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3766,6 +3766,7 @@ impl<'a> Parser<'a> {
projection: vec![SelectItem::Wildcard],
group_by: Vec::new(),
having: None,
qualify: None,
options: Vec::new(),
})),
order_by: Vec::new(),
Expand Down Expand Up @@ -7479,6 +7480,12 @@ impl<'a> Parser<'a> {
None
};

let qualify = if self.parse_keyword(QUALIFY) {
Some(self.parse_expr()?)
} else {
None
};

let options = if self.parse_keyword(OPTIONS) {
self.expect_token(&Token::LParen)?;
let options = self.parse_comma_separated(Self::parse_select_option)?;
Expand All @@ -7495,6 +7502,7 @@ impl<'a> Parser<'a> {
selection,
group_by,
having,
qualify,
options,
})
}
Expand Down
14 changes: 7 additions & 7 deletions src/sql-parser/tests/testdata/alias
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ SELECT 'x' AS val
----
SELECT 'x' AS val
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("val")) }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("val")) }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT 'x' val
----
SELECT 'x' AS val
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("val")) }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("val")) }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT 'x' year
Expand All @@ -39,32 +39,32 @@ SELECT 'x' AS year
----
SELECT 'x' AS "year"
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("year")) }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("year")) }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT 'x' "year"
----
SELECT 'x' AS "year"
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("year")) }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(String("x")), alias: Some(Ident("year")) }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT INTERVAL 'x' YEAR
----
SELECT INTERVAL 'x' YEAR
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(Interval(IntervalValue { value: "x", precision_high: Year, precision_low: Year, fsec_max_precision: None })), alias: None }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Value(Interval(IntervalValue { value: "x", precision_high: Year, precision_low: Year, fsec_max_precision: None })), alias: None }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT year
----
SELECT "year"
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Identifier([Ident("year")]), alias: None }], from: [], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Identifier([Ident("year")]), alias: None }], from: [], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })

parse-statement
SELECT year FROM year
----
SELECT "year" FROM "year"
=>
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Identifier([Ident("year")]), alias: None }], from: [TableWithJoins { relation: Table { name: Name(UnresolvedItemName([Ident("year")])), alias: None }, joins: [] }], selection: None, group_by: [], having: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Select(SelectStatement { query: Query { ctes: Simple([]), body: Select(Select { distinct: None, projection: [Expr { expr: Identifier([Ident("year")]), alias: None }], from: [TableWithJoins { relation: Table { name: Name(UnresolvedItemName([Ident("year")])), alias: None }, joins: [] }], selection: None, group_by: [], having: None, qualify: None, options: [] }), order_by: [], limit: None, offset: None }, as_of: None })
Loading

0 comments on commit ff6b73f

Please sign in to comment.