Skip to content

Commit 2441503

Browse files
authored
feat(window): support named window (#10897)
* support window clause * window clause ast part * named window * add tests * regenerate files * add comments * remove unused trait impl * fix review comments
1 parent f485318 commit 2441503

File tree

24 files changed

+1121
-393
lines changed

24 files changed

+1121
-393
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/query/ast/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ common-io = { path = "../../common/io" }
1616
common-meta-app = { path = "../../meta/app" }
1717

1818
# Crates.io dependencies
19+
enum-as-inner = "0.5.1"
1920
ethnum = "1.3.2"
2021
fast-float = "0.2.0"
2122
itertools = "0.10.5"

src/query/ast/src/ast/expr.rs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use common_exception::Result;
2121
use common_exception::Span;
2222
use common_io::display_decimal_128;
2323
use common_io::display_decimal_256;
24+
use enum_as_inner::EnumAsInner;
2425
use ethnum::i256;
2526

2627
use super::OrderByExpr;
@@ -155,7 +156,7 @@ pub enum Expr {
155156
name: Identifier,
156157
args: Vec<Expr>,
157158
params: Vec<Literal>,
158-
window: Option<WindowSpec>,
159+
window: Option<Window>,
159160
},
160161
/// `CASE ... WHEN ... ELSE ...` expression
161162
Case {
@@ -458,6 +459,23 @@ pub enum TrimWhere {
458459
Trailing,
459460
}
460461

462+
#[derive(Debug, Clone, PartialEq, EnumAsInner)]
463+
pub enum Window {
464+
WindowReference(WindowRef),
465+
WindowSpec(WindowSpec),
466+
}
467+
468+
#[derive(Debug, Clone, PartialEq)]
469+
pub struct WindowDefinition {
470+
pub name: Identifier,
471+
pub spec: WindowSpec,
472+
}
473+
474+
#[derive(Debug, Clone, PartialEq)]
475+
pub struct WindowRef {
476+
pub window_name: Identifier,
477+
}
478+
461479
#[derive(Debug, Clone, PartialEq)]
462480
pub struct WindowSpec {
463481
pub partition_by: Vec<Expr>,
@@ -912,6 +930,28 @@ impl Display for Literal {
912930
}
913931
}
914932

933+
impl Display for WindowDefinition {
934+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
935+
write!(f, "WINDOW {} {}", self.name, self.spec)
936+
}
937+
}
938+
939+
impl Display for Window {
940+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
941+
let window_fmt = match *self {
942+
Window::WindowSpec(ref window_spec) => format!("{}", window_spec),
943+
Window::WindowReference(ref window_ref) => format!("{}", window_ref),
944+
};
945+
write!(f, "{}", window_fmt)
946+
}
947+
}
948+
949+
impl Display for WindowRef {
950+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
951+
write!(f, "WINDOW {}", self.window_name)
952+
}
953+
}
954+
915955
impl Display for WindowSpec {
916956
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
917957
let mut first = true;
@@ -952,28 +992,22 @@ impl Display for WindowSpec {
952992
write!(f, "RANGE")?;
953993
}
954994
}
955-
match (&frame.start_bound, &frame.end_bound) {
956-
(WindowFrameBound::CurrentRow, WindowFrameBound::CurrentRow) => {
957-
write!(f, " CURRENT ROW")?
958-
}
959-
_ => {
960-
let format_frame = |frame: &WindowFrameBound| -> String {
961-
match frame {
962-
WindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
963-
WindowFrameBound::Preceding(None) => "UNBOUNDED PRECEDING".to_string(),
964-
WindowFrameBound::Following(None) => "UNBOUNDED FOLLOWING".to_string(),
965-
WindowFrameBound::Preceding(Some(n)) => format!("{} PRECEDING", n),
966-
WindowFrameBound::Following(Some(n)) => format!("{} FOLLOWING", n),
967-
}
968-
};
969-
write!(
970-
f,
971-
" BETWEEN {} AND {}",
972-
format_frame(&frame.start_bound),
973-
format_frame(&frame.end_bound)
974-
)?
995+
996+
let format_frame = |frame: &WindowFrameBound| -> String {
997+
match frame {
998+
WindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
999+
WindowFrameBound::Preceding(None) => "UNBOUNDED PRECEDING".to_string(),
1000+
WindowFrameBound::Following(None) => "UNBOUNDED FOLLOWING".to_string(),
1001+
WindowFrameBound::Preceding(Some(n)) => format!("{} PRECEDING", n),
1002+
WindowFrameBound::Following(Some(n)) => format!("{} FOLLOWING", n),
9751003
}
976-
}
1004+
};
1005+
write!(
1006+
f,
1007+
" BETWEEN {} AND {}",
1008+
format_frame(&frame.start_bound),
1009+
format_frame(&frame.end_bound)
1010+
)?
9771011
}
9781012
Ok(())
9791013
}

src/query/ast/src/ast/format/ast_format.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
430430
name: &'ast Identifier,
431431
args: &'ast [Expr],
432432
_params: &'ast [Literal],
433-
_over: &'ast Option<WindowSpec>,
433+
_over: &'ast Option<Window>,
434434
) {
435435
let mut children = Vec::with_capacity(args.len());
436436
for arg in args.iter() {
@@ -2215,6 +2215,20 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
22152215
children.push(having_node);
22162216
}
22172217

2218+
if let Some(window_list) = &stmt.window_list {
2219+
let mut window_list_children = Vec::with_capacity(window_list.len());
2220+
for window in window_list {
2221+
self.visit_window_definition(window);
2222+
window_list_children.push(self.children.pop().unwrap());
2223+
}
2224+
let window_list_name = "WindowList".to_string();
2225+
let window_list_format_ctx =
2226+
AstFormatContext::with_children(window_list_name, window_list_children.len());
2227+
let window_list_node =
2228+
FormatTreeNode::with_children(window_list_format_ctx, window_list_children);
2229+
children.push(window_list_node);
2230+
}
2231+
22182232
let name = "SelectQuery".to_string();
22192233
let format_ctx = AstFormatContext::with_children(name, children.len());
22202234
let node = FormatTreeNode::with_children(format_ctx, children);
@@ -2244,6 +2258,17 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
22442258
}
22452259
}
22462260

2261+
fn visit_window_definition(&mut self, window: &'ast WindowDefinition) {
2262+
self.visit_identifier(&window.name);
2263+
let window_name = self.children.pop().unwrap();
2264+
self.visit_window(&Window::WindowSpec(window.spec.clone()));
2265+
let window = self.children.pop().unwrap();
2266+
let name = "Window".to_string();
2267+
let format_ctx = AstFormatContext::with_children(name, 2);
2268+
let node = FormatTreeNode::with_children(format_ctx, vec![window_name, window]);
2269+
self.children.push(node);
2270+
}
2271+
22472272
fn visit_table_reference(&mut self, table: &'ast TableReference) {
22482273
match table {
22492274
TableReference::Table {

src/query/ast/src/ast/query.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::ast::Expr;
2323
use crate::ast::FileLocation;
2424
use crate::ast::Identifier;
2525
use crate::ast::SelectStageOptions;
26+
use crate::ast::WindowDefinition;
2627

2728
/// Root node of a query tree
2829
#[derive(Debug, Clone, PartialEq)]
@@ -85,6 +86,8 @@ pub struct SelectStmt {
8586
pub group_by: Option<GroupBy>,
8687
// `HAVING` clause
8788
pub having: Option<Expr>,
89+
// `WINDOW` clause
90+
pub window_list: Option<Vec<WindowDefinition>>,
8891
}
8992

9093
/// Group by Clause.

src/query/ast/src/parser/expr.rs

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ pub enum ExprElement {
284284
distinct: bool,
285285
name: Identifier,
286286
args: Vec<Expr>,
287-
window: Option<WindowSpec>,
287+
window: Option<Window>,
288288
params: Vec<Literal>,
289289
},
290290
/// `CASE ... WHEN ... ELSE ...` expression
@@ -848,41 +848,6 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
848848
},
849849
);
850850

851-
let window_frame_between = alt((
852-
map(
853-
rule! { BETWEEN ~ #window_frame_bound ~ AND ~ #window_frame_bound },
854-
|(_, s, _, e)| (s, e),
855-
),
856-
map(rule! {#window_frame_bound}, |s| {
857-
(s, WindowFrameBound::Following(None))
858-
}),
859-
));
860-
861-
let window_spec = map(
862-
rule! {
863-
(PARTITION ~ ^BY ~ #comma_separated_list1(subexpr(0)))?
864-
~ ( ORDER ~ ^BY ~ ^#comma_separated_list1(order_by_expr) )?
865-
~ ((ROWS | RANGE) ~ #window_frame_between)?
866-
},
867-
|(opt_partition, opt_order, between)| WindowSpec {
868-
partition_by: opt_partition.map(|x| x.2).unwrap_or_default(),
869-
order_by: opt_order.map(|x| x.2).unwrap_or_default(),
870-
window_frame: between.map(|x| {
871-
let unit = match x.0.kind {
872-
ROWS => WindowFrameUnits::Rows,
873-
RANGE => WindowFrameUnits::Range,
874-
_ => unreachable!(),
875-
};
876-
let bw = x.1;
877-
WindowFrame {
878-
units: unit,
879-
start_bound: bw.0,
880-
end_bound: bw.1,
881-
}
882-
}),
883-
},
884-
);
885-
886851
let function_call = map(
887852
rule! {
888853
#function_name
@@ -901,14 +866,14 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
901866
rule! {
902867
#function_name
903868
~ "(" ~ DISTINCT? ~ #comma_separated_list0(subexpr(0))? ~ ")"
904-
~ (OVER ~ "(" ~ #window_spec ~ ")")
869+
~ (OVER ~ #window_spec_ident)
905870
},
906871
|(name, _, opt_distinct, opt_args, _, window)| ExprElement::FunctionCall {
907872
distinct: opt_distinct.is_some(),
908873
name,
909874
args: opt_args.unwrap_or_default(),
910875
params: vec![],
911-
window: Some(window.2),
876+
window: Some(window.1),
912877
},
913878
);
914879

@@ -1080,6 +1045,7 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
10801045
},
10811046
|(_, not, _, _)| ExprElement::IsDistinctFrom { not: not.is_some() },
10821047
);
1048+
10831049
let (rest, (span, elem)) = consumed(alt((
10841050
// Note: each `alt` call supports maximum of 21 parsers
10851051
rule!(
@@ -1125,26 +1091,6 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
11251091
Ok((rest, WithSpan { span, elem }))
11261092
}
11271093

1128-
pub fn window_frame_bound(i: Input) -> IResult<WindowFrameBound> {
1129-
alt((
1130-
value(WindowFrameBound::CurrentRow, rule! { CURRENT ~ ROW }),
1131-
map(rule! { #subexpr(0) ~ PRECEDING }, |(expr, _)| {
1132-
WindowFrameBound::Preceding(Some(Box::new(expr)))
1133-
}),
1134-
value(
1135-
WindowFrameBound::Preceding(None),
1136-
rule! { UNBOUNDED ~ PRECEDING },
1137-
),
1138-
map(rule! { #subexpr(0) ~ FOLLOWING }, |(expr, _)| {
1139-
WindowFrameBound::Following(Some(Box::new(expr)))
1140-
}),
1141-
value(
1142-
WindowFrameBound::Following(None),
1143-
rule! { UNBOUNDED ~ FOLLOWING },
1144-
),
1145-
))(i)
1146-
}
1147-
11481094
pub fn unary_op(i: Input) -> IResult<UnaryOperator> {
11491095
// Plus and Minus are parsed as binary op at first.
11501096
alt((

0 commit comments

Comments
 (0)