Skip to content

Commit 4648951

Browse files
committed
rebasing to main
1 parent f5b818e commit 4648951

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

src/ast/mod.rs

+29-12
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,17 @@ pub enum ExtractSyntax {
493493
Comma,
494494
}
495495

496+
/// The syntax used in a CEIL or FLOOR expression.
497+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
498+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
499+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
500+
pub enum CeilFloorKind {
501+
/// `CEIL( <expr> TO <DateTimeField>)`
502+
DateTimeField(DateTimeField),
503+
/// `CEIL( <expr> [, <scale>])`
504+
Scale(Value),
505+
}
506+
496507
/// An SQL expression of any type.
497508
///
498509
/// The parser does not distinguish between expressions of different types
@@ -667,16 +678,22 @@ pub enum Expr {
667678
/// ```sql
668679
/// CEIL(<expr> [TO DateTimeField])
669680
/// ```
681+
/// ```sql
682+
/// CEIL( <input_expr> [, <scale_expr> ] )
683+
/// ```
670684
Ceil {
671685
expr: Box<Expr>,
672-
field: DateTimeField,
686+
field: CeilFloorKind,
673687
},
674688
/// ```sql
675689
/// FLOOR(<expr> [TO DateTimeField])
676690
/// ```
691+
/// ```sql
692+
/// FLOOR( <input_expr> [, <scale_expr> ] )
693+
///
677694
Floor {
678695
expr: Box<Expr>,
679-
field: DateTimeField,
696+
field: CeilFloorKind,
680697
},
681698
/// ```sql
682699
/// POSITION(<expr> in <expr>)
@@ -1223,20 +1240,20 @@ impl fmt::Display for Expr {
12231240
ExtractSyntax::From => write!(f, "EXTRACT({field} FROM {expr})"),
12241241
ExtractSyntax::Comma => write!(f, "EXTRACT({field}, {expr})"),
12251242
},
1226-
Expr::Ceil { expr, field } => {
1227-
if field == &DateTimeField::NoDateTime {
1243+
Expr::Ceil { expr, field } => match field {
1244+
CeilFloorKind::DateTimeField(DateTimeField::NoDateTime) => {
12281245
write!(f, "CEIL({expr})")
1229-
} else {
1230-
write!(f, "CEIL({expr} TO {field})")
12311246
}
1232-
}
1233-
Expr::Floor { expr, field } => {
1234-
if field == &DateTimeField::NoDateTime {
1247+
CeilFloorKind::DateTimeField(dt_field) => write!(f, "CEIL({expr} TO {dt_field})"),
1248+
CeilFloorKind::Scale(s) => write!(f, "CEIL({expr}, {s})"),
1249+
},
1250+
Expr::Floor { expr, field } => match field {
1251+
CeilFloorKind::DateTimeField(DateTimeField::NoDateTime) => {
12351252
write!(f, "FLOOR({expr})")
1236-
} else {
1237-
write!(f, "FLOOR({expr} TO {field})")
12381253
}
1239-
}
1254+
CeilFloorKind::DateTimeField(dt_field) => write!(f, "FLOOR({expr} TO {dt_field})"),
1255+
CeilFloorKind::Scale(s) => write!(f, "FLOOR({expr}, {s})"),
1256+
},
12401257
Expr::Position { expr, r#in } => write!(f, "POSITION({expr} IN {in})"),
12411258
Expr::Collate { expr, collation } => write!(f, "{expr} COLLATE {collation}"),
12421259
Expr::Nested(ast) => write!(f, "({ast})"),

src/parser/mod.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -1708,12 +1708,22 @@ impl<'a> Parser<'a> {
17081708
self.expect_token(&Token::LParen)?;
17091709
let expr = self.parse_expr()?;
17101710
// Parse `CEIL/FLOOR(expr)`
1711-
let mut field = DateTimeField::NoDateTime;
1712-
let keyword_to = self.parse_keyword(Keyword::TO);
1713-
if keyword_to {
1711+
let field = if self.parse_keyword(Keyword::TO) {
17141712
// Parse `CEIL/FLOOR(expr TO DateTimeField)`
1715-
field = self.parse_date_time_field()?;
1716-
}
1713+
CeilFloorKind::DateTimeField(self.parse_date_time_field()?)
1714+
} else if self.consume_token(&Token::Comma) {
1715+
// Parse `CEIL/FLOOR(expr, scale)`
1716+
match self.parse_value()? {
1717+
Value::Number(n, s) => CeilFloorKind::Scale(Value::Number(n, s)),
1718+
_ => {
1719+
return Err(ParserError::ParserError(
1720+
"Scale field can only be of number type".to_string(),
1721+
))
1722+
}
1723+
}
1724+
} else {
1725+
CeilFloorKind::DateTimeField(DateTimeField::NoDateTime)
1726+
};
17171727
self.expect_token(&Token::RParen)?;
17181728
if is_ceil {
17191729
Ok(Expr::Ceil {

tests/sqlparser_common.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -2494,14 +2494,52 @@ fn parse_floor_number() {
24942494
verified_stmt("SELECT FLOOR(float_column) FROM my_table");
24952495
}
24962496

2497+
#[test]
2498+
fn parse_ceil_number_scale() {
2499+
verified_stmt("SELECT CEIL(1.5, 1)");
2500+
verified_stmt("SELECT CEIL(float_column, 3) FROM my_table");
2501+
}
2502+
2503+
#[test]
2504+
fn parse_floor_number_scale() {
2505+
verified_stmt("SELECT FLOOR(1.5, 1)");
2506+
verified_stmt("SELECT FLOOR(float_column, 3) FROM my_table");
2507+
}
2508+
2509+
#[test]
2510+
fn parse_ceil_scale() {
2511+
let sql = "SELECT CEIL(d, 2)";
2512+
let select = verified_only_select(sql);
2513+
assert_eq!(
2514+
&Expr::Ceil {
2515+
expr: Box::new(Expr::Identifier(Ident::new("d"))),
2516+
field: CeilFloorKind::Scale(Value::Number(2.to_string(), false)),
2517+
},
2518+
expr_from_projection(only(&select.projection)),
2519+
);
2520+
}
2521+
2522+
#[test]
2523+
fn parse_floor_scale() {
2524+
let sql = "SELECT FLOOR(d, 2)";
2525+
let select = verified_only_select(sql);
2526+
assert_eq!(
2527+
&Expr::Floor {
2528+
expr: Box::new(Expr::Identifier(Ident::new("d"))),
2529+
field: CeilFloorKind::Scale(Value::Number(2.to_string(), false)),
2530+
},
2531+
expr_from_projection(only(&select.projection)),
2532+
);
2533+
}
2534+
24972535
#[test]
24982536
fn parse_ceil_datetime() {
24992537
let sql = "SELECT CEIL(d TO DAY)";
25002538
let select = verified_only_select(sql);
25012539
assert_eq!(
25022540
&Expr::Ceil {
25032541
expr: Box::new(Expr::Identifier(Ident::new("d"))),
2504-
field: DateTimeField::Day,
2542+
field: CeilFloorKind::DateTimeField(DateTimeField::Day),
25052543
},
25062544
expr_from_projection(only(&select.projection)),
25072545
);
@@ -2528,7 +2566,7 @@ fn parse_floor_datetime() {
25282566
assert_eq!(
25292567
&Expr::Floor {
25302568
expr: Box::new(Expr::Identifier(Ident::new("d"))),
2531-
field: DateTimeField::Day,
2569+
field: CeilFloorKind::DateTimeField(DateTimeField::Day),
25322570
},
25332571
expr_from_projection(only(&select.projection)),
25342572
);

0 commit comments

Comments
 (0)