Named window frames (#881)

* after over clause, named window can be parsed with window ... as after having clause

* Lint errors are fixed

* Support for multiple windows

* fix lint errors

* simplifications

* rename function

* Rewrite named window search in functional style

* Test added and some minor changes

* Minor changes on tests and namings, and semantic check is removed

---------

Co-authored-by: Mustafa Akur <mustafa.akur@synnada.ai>
Co-authored-by: Mehmet Ozan Kabak <ozankabak@gmail.com>
This commit is contained in:
Berkay Şahin 2023-05-18 22:00:24 +03:00 committed by GitHub
parent 1b86abebe2
commit ef46cd3752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 225 additions and 37 deletions

View file

@ -19,7 +19,6 @@
//! dialect-specific parsing rules).
use matches::assert_matches;
use sqlparser::ast::SelectItem::UnnamedExpr;
use sqlparser::ast::TableFactor::Pivot;
use sqlparser::ast::*;
@ -251,6 +250,7 @@ fn parse_update_set_from() {
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![],
qualify: None
}))),
order_by: vec![],
@ -1721,7 +1721,7 @@ fn parse_select_qualify() {
left: Box::new(Expr::Function(Function {
name: ObjectName(vec![Ident::new("ROW_NUMBER")]),
args: vec![],
over: Some(WindowSpec {
over: Some(WindowType::WindowSpec(WindowSpec {
partition_by: vec![Expr::Identifier(Ident::new("p"))],
order_by: vec![OrderByExpr {
expr: Expr::Identifier(Ident::new("o")),
@ -1729,7 +1729,7 @@ fn parse_select_qualify() {
nulls_first: None,
}],
window_frame: None,
}),
})),
distinct: false,
special: false,
order_by: vec![],
@ -3295,7 +3295,7 @@ fn parse_window_functions() {
&Expr::Function(Function {
name: ObjectName(vec![Ident::new("row_number")]),
args: vec![],
over: Some(WindowSpec {
over: Some(WindowType::WindowSpec(WindowSpec {
partition_by: vec![],
order_by: vec![OrderByExpr {
expr: Expr::Identifier(Ident::new("dt")),
@ -3303,7 +3303,7 @@ fn parse_window_functions() {
nulls_first: None,
}],
window_frame: None,
}),
})),
distinct: false,
special: false,
order_by: vec![],
@ -3312,6 +3312,128 @@ fn parse_window_functions() {
);
}
#[test]
fn test_parse_named_window() {
let sql = "SELECT \
MIN(c12) OVER window1 AS min1, \
MAX(c12) OVER window2 AS max1 \
FROM aggregate_test_100 \
WINDOW window1 AS (ORDER BY C12), \
window2 AS (PARTITION BY C11) \
ORDER BY C3";
let actual_select_only = verified_only_select(sql);
let expected = Select {
distinct: None,
top: None,
projection: vec![
SelectItem::ExprWithAlias {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident {
value: "MIN".to_string(),
quote_style: None,
}]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
over: Some(WindowType::NamedWindow(Ident {
value: "window1".to_string(),
quote_style: None,
})),
distinct: false,
special: false,
}),
alias: Ident {
value: "min1".to_string(),
quote_style: None,
},
},
SelectItem::ExprWithAlias {
expr: Expr::Function(Function {
name: ObjectName(vec![Ident {
value: "MAX".to_string(),
quote_style: None,
}]),
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
Expr::Identifier(Ident {
value: "c12".to_string(),
quote_style: None,
}),
))],
over: Some(WindowType::NamedWindow(Ident {
value: "window2".to_string(),
quote_style: None,
})),
distinct: false,
special: false,
}),
alias: Ident {
value: "max1".to_string(),
quote_style: None,
},
},
],
into: None,
from: vec![TableWithJoins {
relation: TableFactor::Table {
name: ObjectName(vec![Ident {
value: "aggregate_test_100".to_string(),
quote_style: None,
}]),
alias: None,
args: None,
with_hints: vec![],
},
joins: vec![],
}],
lateral_views: vec![],
selection: None,
group_by: vec![],
cluster_by: vec![],
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![
NamedWindowDefinition(
Ident {
value: "window1".to_string(),
quote_style: None,
},
WindowSpec {
partition_by: vec![],
order_by: vec![OrderByExpr {
expr: Expr::Identifier(Ident {
value: "C12".to_string(),
quote_style: None,
}),
asc: None,
nulls_first: None,
}],
window_frame: None,
},
),
NamedWindowDefinition(
Ident {
value: "window2".to_string(),
quote_style: None,
},
WindowSpec {
partition_by: vec![Expr::Identifier(Ident {
value: "C11".to_string(),
quote_style: None,
})],
order_by: vec![],
window_frame: None,
},
),
],
qualify: None,
};
assert_eq!(actual_select_only, expected);
}
#[test]
fn parse_aggregate_with_group_by() {
let sql = "SELECT a, COUNT(1), MIN(b), MAX(b) FROM foo GROUP BY a";
@ -3659,6 +3781,7 @@ fn parse_interval_and_or_xor() {
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![],
qualify: None,
}))),
order_by: vec![],
@ -5929,6 +6052,7 @@ fn parse_merge() {
distribute_by: vec![],
sort_by: vec![],
having: None,
named_window: vec![],
qualify: None,
}))),
order_by: vec![],