Skip to content

Commit 04ac467

Browse files
committed
refactor: type aggregate and window binding
1 parent 70cb927 commit 04ac467

8 files changed

Lines changed: 156 additions & 117 deletions

File tree

src/binder/expr.rs

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -476,76 +476,60 @@ impl<'a, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'a, '_, T
476476
})
477477
}
478478

479-
pub(crate) fn bind_function_call(
479+
pub(crate) fn bind_aggregate_function(
480480
&mut self,
481-
function_name: String,
482-
mut args: Vec<ScalarExpression>,
481+
kind: AggKind,
482+
args: Vec<ScalarExpression>,
483483
is_distinct: bool,
484484
arena: &mut PlanArena,
485485
) -> Result<ScalarExpression, DatabaseError> {
486-
match function_name.as_str() {
487-
"count" => {
486+
let ty = match kind {
487+
AggKind::Count => {
488488
if args.len() != 1 {
489489
return Err(DatabaseError::MisMatch("number of count() parameters", "1"));
490490
}
491-
return Ok(ScalarExpression::AggCall {
492-
distinct: is_distinct,
493-
kind: AggKind::Count,
494-
args,
495-
ty: LogicalType::Integer,
496-
});
491+
LogicalType::Integer
497492
}
498-
"sum" => {
493+
AggKind::Sum => {
499494
if args.len() != 1 {
500495
return Err(DatabaseError::MisMatch("number of sum() parameters", "1"));
501496
}
502-
let ty = args[0].return_type(arena).into_owned();
503-
504-
return Ok(ScalarExpression::AggCall {
505-
distinct: is_distinct,
506-
kind: AggKind::Sum,
507-
args,
508-
ty,
509-
});
497+
args[0].return_type(arena).into_owned()
510498
}
511-
"min" => {
499+
AggKind::Min => {
512500
if args.len() != 1 {
513501
return Err(DatabaseError::MisMatch("number of min() parameters", "1"));
514502
}
515-
let ty = args[0].return_type(arena).into_owned();
516-
517-
return Ok(ScalarExpression::AggCall {
518-
distinct: is_distinct,
519-
kind: AggKind::Min,
520-
args,
521-
ty,
522-
});
503+
args[0].return_type(arena).into_owned()
523504
}
524-
"max" => {
505+
AggKind::Max => {
525506
if args.len() != 1 {
526507
return Err(DatabaseError::MisMatch("number of max() parameters", "1"));
527508
}
528-
let ty = args[0].return_type(arena).into_owned();
529-
530-
return Ok(ScalarExpression::AggCall {
531-
distinct: is_distinct,
532-
kind: AggKind::Max,
533-
args,
534-
ty,
535-
});
509+
args[0].return_type(arena).into_owned()
536510
}
537-
"avg" => {
511+
AggKind::Avg => {
538512
if args.len() != 1 {
539513
return Err(DatabaseError::MisMatch("number of avg() parameters", "1"));
540514
}
541-
542-
return Ok(ScalarExpression::AggCall {
543-
distinct: is_distinct,
544-
kind: AggKind::Avg,
545-
args,
546-
ty: LogicalType::Double,
547-
});
515+
LogicalType::Double
548516
}
517+
};
518+
Ok(ScalarExpression::AggCall {
519+
distinct: is_distinct,
520+
kind,
521+
args,
522+
ty,
523+
})
524+
}
525+
526+
pub(crate) fn bind_function_call(
527+
&mut self,
528+
function_name: String,
529+
mut args: Vec<ScalarExpression>,
530+
arena: &mut PlanArena,
531+
) -> Result<ScalarExpression, DatabaseError> {
532+
match function_name.as_str() {
549533
"if" => {
550534
if args.len() != 3 {
551535
return Err(DatabaseError::MisMatch("number of if() parameters", "3"));

src/binder/parser.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ use crate::catalog::{ColumnCatalog, ColumnDesc, ColumnRef, TableName};
2323
use crate::db::{BindSource, DBTransaction, Database, DatabaseIter, TransactionIter};
2424
use crate::errors::{DatabaseError, SqlErrorSpan};
2525
use crate::expression;
26+
use crate::expression::agg::AggKind;
2627
use crate::expression::simplify::ConstantCalculator;
2728
use crate::expression::visitor_mut::ExprVisitorMut;
29+
use crate::expression::window::WindowFunctionKind;
2830
use crate::expression::{AliasType, ScalarExpression};
2931
use crate::iter_ext::Itertools;
3032
use crate::parser::parse_sql;
@@ -2440,18 +2442,30 @@ impl<'a, 'parent, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<
24402442
.to_string(),
24412443
));
24422444
}
2445+
let Some(kind) = WindowFunctionKind::from_name(&function_name) else {
2446+
return Err(attach_span_if_absent(
2447+
DatabaseError::UnsupportedStmt(format!(
2448+
"window function `{function_name}` is not supported"
2449+
)),
2450+
func_span,
2451+
));
2452+
};
24432453
return self
2444-
.bind_window_call(function_name, args, is_distinct, over, arena)
2454+
.bind_window_call(kind, args, is_distinct, over, arena)
24452455
.map_err(|err| attach_span_if_absent(err, func_span));
24462456
}
24472457

2448-
self.bind_function_call(function_name, args, is_distinct, arena)
2449-
.map_err(|err| attach_span_if_absent(err, func_span))
2458+
let result = if let Some(kind) = AggKind::from_name(&function_name) {
2459+
self.bind_aggregate_function(kind, args, is_distinct, arena)
2460+
} else {
2461+
self.bind_function_call(function_name, args, arena)
2462+
};
2463+
result.map_err(|err| attach_span_if_absent(err, func_span))
24502464
}
24512465

24522466
fn bind_window_call(
24532467
&mut self,
2454-
function_name: String,
2468+
kind: WindowFunctionKind,
24552469
args: Vec<ScalarExpression>,
24562470
is_distinct: bool,
24572471
over: &WindowType,
@@ -2502,7 +2516,7 @@ impl<'a, 'parent, T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<
25022516
))
25032517
})
25042518
.collect::<Result<Vec<_>, DatabaseError>>()?;
2505-
self.bind_window_function(function_name, args, partition_by, order_by, arena)
2519+
self.bind_window_function(kind, args, partition_by, order_by, arena)
25062520
}
25072521

25082522
pub fn bind_set_expr(

src/binder/window.rs

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ struct WindowGroup {
9494
impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A> {
9595
pub(crate) fn bind_window_function(
9696
&mut self,
97-
function_name: String,
97+
kind: WindowFunctionKind,
9898
args: Vec<ScalarExpression>,
9999
partition_by: Vec<ScalarExpression>,
100100
order_by: Vec<SortField>,
@@ -120,34 +120,25 @@ impl<T: Transaction, A: AsRef<[(&'static str, DataValue)]>> Binder<'_, '_, T, A>
120120
}
121121
}
122122

123-
let (kind, args, ty) = match function_name.as_str() {
124-
"row_number" | "rank" | "dense_rank" => {
123+
let (args, ty) = match kind {
124+
WindowFunctionKind::RowNumber
125+
| WindowFunctionKind::Rank
126+
| WindowFunctionKind::DenseRank => {
125127
if !args.is_empty() {
126128
return Err(DatabaseError::MisMatch(
127129
"number of ranking function parameters",
128130
"0",
129131
));
130132
}
131-
let kind = match function_name.as_str() {
132-
"row_number" => WindowFunctionKind::RowNumber,
133-
"rank" => WindowFunctionKind::Rank,
134-
"dense_rank" => WindowFunctionKind::DenseRank,
135-
_ => unreachable!(),
136-
};
137-
(kind, args, LogicalType::Bigint)
133+
(args, LogicalType::Bigint)
138134
}
139-
"count" | "sum" | "avg" | "min" | "max" => {
140-
let ScalarExpression::AggCall { kind, args, ty, .. } =
141-
self.bind_function_call(function_name, args, false, arena)?
135+
WindowFunctionKind::Aggregate(agg_kind) => {
136+
let ScalarExpression::AggCall { args, ty, .. } =
137+
self.bind_aggregate_function(agg_kind, args, false, arena)?
142138
else {
143139
unreachable!()
144140
};
145-
(WindowFunctionKind::Aggregate(kind), args, ty)
146-
}
147-
_ => {
148-
return Err(DatabaseError::UnsupportedStmt(format!(
149-
"window function `{function_name}` is not supported"
150-
)))
141+
(args, ty)
151142
}
152143
};
153144

src/expression/agg.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,27 @@ pub enum AggKind {
2424
}
2525

2626
impl AggKind {
27+
pub(crate) fn from_name(name: &str) -> Option<Self> {
28+
match name {
29+
"avg" => Some(Self::Avg),
30+
"max" => Some(Self::Max),
31+
"min" => Some(Self::Min),
32+
"sum" => Some(Self::Sum),
33+
"count" => Some(Self::Count),
34+
_ => None,
35+
}
36+
}
37+
38+
pub(crate) fn name(self) -> &'static str {
39+
match self {
40+
Self::Avg => "avg",
41+
Self::Max => "max",
42+
Self::Min => "min",
43+
Self::Sum => "sum",
44+
Self::Count => "count",
45+
}
46+
}
47+
2748
pub fn allow_distinct(&self) -> bool {
2849
match self {
2950
AggKind::Avg => false,

src/expression/mod.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -784,14 +784,7 @@ impl ScalarExpression {
784784
.iter()
785785
.map(|expr| expr.output_name_by(fn_display))
786786
.join(", ");
787-
let function = match window.function.kind {
788-
window::WindowFunctionKind::RowNumber => "row_number".to_string(),
789-
window::WindowFunctionKind::Rank => "rank".to_string(),
790-
window::WindowFunctionKind::DenseRank => "dense_rank".to_string(),
791-
window::WindowFunctionKind::Aggregate(kind) => {
792-
format!("{kind:?}").to_lowercase()
793-
}
794-
};
787+
let function = window.function.kind.name();
795788
let mut spec = Vec::new();
796789
if !window.spec.partition_by.is_empty() {
797790
spec.push(format!(

src/expression/window.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,26 @@ pub enum WindowFunctionKind {
2626
Aggregate(AggKind),
2727
}
2828

29+
impl WindowFunctionKind {
30+
pub(crate) fn from_name(name: &str) -> Option<Self> {
31+
match name {
32+
"row_number" => Some(Self::RowNumber),
33+
"rank" => Some(Self::Rank),
34+
"dense_rank" => Some(Self::DenseRank),
35+
name => AggKind::from_name(name).map(Self::Aggregate),
36+
}
37+
}
38+
39+
pub(crate) fn name(self) -> &'static str {
40+
match self {
41+
Self::RowNumber => "row_number",
42+
Self::Rank => "rank",
43+
Self::DenseRank => "dense_rank",
44+
Self::Aggregate(kind) => kind.name(),
45+
}
46+
}
47+
}
48+
2949
#[derive(Debug, Clone, PartialEq, Eq, Hash, ReferenceSerialization)]
3050
pub struct WindowFunction {
3151
pub kind: WindowFunctionKind,

0 commit comments

Comments
 (0)