Skip to content

Commit 7a1716d

Browse files
committed
adding support for scale in CEIL and FLOOR functions
1 parent 1e209d8 commit 7a1716d

File tree

3 files changed

+76
-17
lines changed

3 files changed

+76
-17
lines changed

src/ast/mod.rs

+27-10
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,17 @@ pub enum CastKind {
477477
DoubleColon,
478478
}
479479

480+
/// The syntax used in a CEIL or FLOOR expression.
481+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
482+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
483+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
484+
pub enum CeilFloorKind {
485+
/// `CEIL( <expr> TO <DateTimeField>)`
486+
DateTimeField(DateTimeField),
487+
/// `CEIL( <expr> [, <scale>])`
488+
Scale(Value),
489+
}
490+
480491
/// An SQL expression of any type.
481492
///
482493
/// The parser does not distinguish between expressions of different types
@@ -649,16 +660,22 @@ pub enum Expr {
649660
/// ```sql
650661
/// CEIL(<expr> [TO DateTimeField])
651662
/// ```
663+
/// ```sql
664+
/// CEIL( <input_expr> [, <scale_expr> ] )
665+
/// ```
652666
Ceil {
653667
expr: Box<Expr>,
654-
field: DateTimeField,
668+
field: CeilFloorKind,
655669
},
656670
/// ```sql
657671
/// FLOOR(<expr> [TO DateTimeField])
658672
/// ```
673+
/// ```sql
674+
/// FLOOR( <input_expr> [, <scale_expr> ] )
675+
///
659676
Floor {
660677
expr: Box<Expr>,
661-
field: DateTimeField,
678+
field: CeilFloorKind,
662679
},
663680
/// ```sql
664681
/// POSITION(<expr> in <expr>)
@@ -1199,17 +1216,17 @@ impl fmt::Display for Expr {
11991216
},
12001217
Expr::Extract { field, expr } => write!(f, "EXTRACT({field} FROM {expr})"),
12011218
Expr::Ceil { expr, field } => {
1202-
if field == &DateTimeField::NoDateTime {
1203-
write!(f, "CEIL({expr})")
1204-
} else {
1205-
write!(f, "CEIL({expr} TO {field})")
1219+
match field {
1220+
CeilFloorKind::DateTimeField(DateTimeField::NoDateTime) => write!(f, "CEIL({expr})"),
1221+
CeilFloorKind::DateTimeField(dt_field) => write!(f, "CEIL({expr} TO {dt_field})"),
1222+
CeilFloorKind::Scale(s) => write!(f, "CEIL({expr}, {s})"),
12061223
}
12071224
}
12081225
Expr::Floor { expr, field } => {
1209-
if field == &DateTimeField::NoDateTime {
1210-
write!(f, "FLOOR({expr})")
1211-
} else {
1212-
write!(f, "FLOOR({expr} TO {field})")
1226+
match field {
1227+
CeilFloorKind::DateTimeField(DateTimeField::NoDateTime) => write!(f, "FLOOR({expr})"),
1228+
CeilFloorKind::DateTimeField(dt_field) => write!(f, "FLOOR({expr} TO {dt_field})"),
1229+
CeilFloorKind::Scale(s) => write!(f, "FLOOR({expr}, {s})"),
12131230
}
12141231
}
12151232
Expr::Position { expr, r#in } => write!(f, "POSITION({expr} IN {in})"),

src/parser/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -1695,12 +1695,16 @@ impl<'a> Parser<'a> {
16951695
self.expect_token(&Token::LParen)?;
16961696
let expr = self.parse_expr()?;
16971697
// Parse `CEIL/FLOOR(expr)`
1698-
let mut field = DateTimeField::NoDateTime;
1699-
let keyword_to = self.parse_keyword(Keyword::TO);
1700-
if keyword_to {
1698+
let field = if self.parse_keyword(Keyword::TO) {
17011699
// Parse `CEIL/FLOOR(expr TO DateTimeField)`
1702-
field = self.parse_date_time_field()?;
1703-
}
1700+
CeilFloorKind::DateTimeField(self.parse_date_time_field()?)
1701+
} else if self.consume_token(&Token::Comma) {
1702+
// Parse `CEIL/FLOOR(expr, scale)`
1703+
match self.parse_value()? {
1704+
Value::Number(n, s) => CeilFloorKind::Scale(Value::Number(n, s)),
1705+
_ => return Err(ParserError::ParserError("Scale field can only be of number type".to_string())),
1706+
}
1707+
} else { CeilFloorKind::DateTimeField(DateTimeField::NoDateTime) };
17041708
self.expect_token(&Token::RParen)?;
17051709
if is_ceil {
17061710
Ok(Expr::Ceil {

tests/sqlparser_common.rs

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

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

0 commit comments

Comments
 (0)