Skip to content

Commit 0e23acc

Browse files
committed
Test added and some minor changes
1 parent d72e84d commit 0e23acc

File tree

4 files changed

+155
-8
lines changed

4 files changed

+155
-8
lines changed

src/ast/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ pub enum WindowType {
928928
impl Display for WindowType {
929929
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
930930
match self {
931-
WindowType::WindowSpec(spec) => write!(f, "{}", spec),
931+
WindowType::WindowSpec(spec) => write!(f, "({})", spec),
932932
WindowType::NamedWindow(name) => write!(f, "{}", name),
933933
}
934934
}
@@ -3401,7 +3401,7 @@ impl fmt::Display for Function {
34013401
)?;
34023402

34033403
if let Some(o) = &self.over {
3404-
write!(f, " OVER ({o})")?;
3404+
write!(f, " OVER {o}")?;
34053405
}
34063406
}
34073407

src/ast/query.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,6 @@ pub struct Select {
222222
pub qualify: Option<Expr>,
223223
}
224224

225-
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
226-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
227-
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
228-
pub struct IdentWindow(pub Ident, pub WindowSpec);
229-
230225
impl fmt::Display for Select {
231226
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232227
write!(f, "SELECT")?;
@@ -276,6 +271,9 @@ impl fmt::Display for Select {
276271
if let Some(ref having) = self.having {
277272
write!(f, " HAVING {having}")?;
278273
}
274+
if !self.named_window.is_empty() {
275+
write!(f, " WINDOW {}", display_comma_separated(&self.named_window))?;
276+
}
279277
if let Some(ref qualify) = self.qualify {
280278
write!(f, " QUALIFY {qualify}")?;
281279
}
@@ -318,6 +316,17 @@ impl fmt::Display for LateralView {
318316
}
319317
}
320318

319+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
320+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
321+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
322+
pub struct IdentWindow(pub Ident, pub WindowSpec);
323+
324+
impl fmt::Display for IdentWindow {
325+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
326+
write!(f, "{} AS ({})", self.0, self.1)
327+
}
328+
}
329+
321330
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
322331
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
323332
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/parser.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5252,6 +5252,8 @@ impl<'a> Parser<'a> {
52525252
} else {
52535253
vec![]
52545254
};
5255+
// If the projection is done over a named window,
5256+
// that window name must be defined. That check is done here.
52555257
for proj in &projection {
52565258
if let SelectItem::ExprWithAlias {
52575259
expr: Expr::Function(f),

tests/sqlparser_common.rs

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
//! dialect-specific parsing rules).
2020
2121
use matches::assert_matches;
22-
2322
use sqlparser::ast::SelectItem::UnnamedExpr;
2423
use sqlparser::ast::TableFactor::Pivot;
2524
use sqlparser::ast::*;
@@ -3276,6 +3275,143 @@ fn parse_window_functions() {
32763275
);
32773276
}
32783277

3278+
#[test]
3279+
fn parse_named_window() {
3280+
let sql = "SELECT \
3281+
MIN(c12) OVER window1 AS min1, \
3282+
MAX(c12) OVER window2 AS max1 \
3283+
FROM aggregate_test_100 \
3284+
WINDOW window1 AS (ORDER BY C12), \
3285+
window2 AS (PARTITION BY C11) \
3286+
ORDER BY C3";
3287+
let actual = Parser::parse_sql(&GenericDialect {}, sql).unwrap();
3288+
let expected = vec![Statement::Query(Box::new(Query {
3289+
with: None,
3290+
body: Box::new(SetExpr::Select(Box::new(Select {
3291+
distinct: None,
3292+
top: None,
3293+
projection: vec![
3294+
SelectItem::ExprWithAlias {
3295+
expr: Expr::Function(Function {
3296+
name: ObjectName(vec![Ident {
3297+
value: "MIN".to_string(),
3298+
quote_style: None,
3299+
}]),
3300+
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
3301+
Expr::Identifier(Ident {
3302+
value: "c12".to_string(),
3303+
quote_style: None,
3304+
}),
3305+
))],
3306+
over: Some(WindowType::NamedWindow(Ident {
3307+
value: "window1".to_string(),
3308+
quote_style: None,
3309+
})),
3310+
distinct: false,
3311+
special: false,
3312+
}),
3313+
alias: Ident {
3314+
value: "min1".to_string(),
3315+
quote_style: None,
3316+
},
3317+
},
3318+
SelectItem::ExprWithAlias {
3319+
expr: Expr::Function(Function {
3320+
name: ObjectName(vec![Ident {
3321+
value: "MAX".to_string(),
3322+
quote_style: None,
3323+
}]),
3324+
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(
3325+
Expr::Identifier(Ident {
3326+
value: "c12".to_string(),
3327+
quote_style: None,
3328+
}),
3329+
))],
3330+
over: Some(WindowType::NamedWindow(Ident {
3331+
value: "window2".to_string(),
3332+
quote_style: None,
3333+
})),
3334+
distinct: false,
3335+
special: false,
3336+
}),
3337+
alias: Ident {
3338+
value: "max1".to_string(),
3339+
quote_style: None,
3340+
},
3341+
},
3342+
],
3343+
into: None,
3344+
from: vec![TableWithJoins {
3345+
relation: TableFactor::Table {
3346+
name: ObjectName(vec![Ident {
3347+
value: "aggregate_test_100".to_string(),
3348+
quote_style: None,
3349+
}]),
3350+
alias: None,
3351+
args: None,
3352+
with_hints: vec![],
3353+
},
3354+
joins: vec![],
3355+
}],
3356+
lateral_views: vec![],
3357+
selection: None,
3358+
group_by: vec![],
3359+
cluster_by: vec![],
3360+
distribute_by: vec![],
3361+
sort_by: vec![],
3362+
having: None,
3363+
named_window: vec![
3364+
IdentWindow(
3365+
Ident {
3366+
value: "window1".to_string(),
3367+
quote_style: None,
3368+
},
3369+
WindowSpec {
3370+
partition_by: vec![],
3371+
order_by: vec![OrderByExpr {
3372+
expr: Expr::Identifier(Ident {
3373+
value: "C12".to_string(),
3374+
quote_style: None,
3375+
}),
3376+
asc: None,
3377+
nulls_first: None,
3378+
}],
3379+
window_frame: None,
3380+
},
3381+
),
3382+
IdentWindow(
3383+
Ident {
3384+
value: "window2".to_string(),
3385+
quote_style: None,
3386+
},
3387+
WindowSpec {
3388+
partition_by: vec![Expr::Identifier(Ident {
3389+
value: "C11".to_string(),
3390+
quote_style: None,
3391+
})],
3392+
order_by: vec![],
3393+
window_frame: None,
3394+
},
3395+
),
3396+
],
3397+
qualify: None,
3398+
}))),
3399+
order_by: vec![OrderByExpr {
3400+
expr: Expr::Identifier(Ident {
3401+
value: "C3".to_string(),
3402+
quote_style: None,
3403+
}),
3404+
asc: None,
3405+
nulls_first: None,
3406+
}],
3407+
limit: None,
3408+
offset: None,
3409+
fetch: None,
3410+
locks: vec![],
3411+
}))];
3412+
assert_eq!(actual, expected);
3413+
}
3414+
32793415
#[test]
32803416
fn parse_aggregate_with_group_by() {
32813417
let sql = "SELECT a, COUNT(1), MIN(b), MAX(b) FROM foo GROUP BY a";

0 commit comments

Comments
 (0)