Skip to content

Commit 97ecd7f

Browse files
authored
feat(query): support function time_slice(date_or_time_expr, slice_length, IntervalKind [, start_or_end]) (#18570)
* feat(query): support time_slice function * fix conversation * refactor
1 parent 0811612 commit 97ecd7f

File tree

15 files changed

+673
-5
lines changed

15 files changed

+673
-5
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ pub enum Expr {
267267
unit: IntervalKind,
268268
date: Box<Expr>,
269269
},
270+
TimeSlice {
271+
span: Span,
272+
date: Box<Expr>,
273+
slice_length: u64,
274+
unit: IntervalKind,
275+
start_or_end: String,
276+
},
270277
LastDay {
271278
span: Span,
272279
unit: IntervalKind,
@@ -329,6 +336,7 @@ impl Expr {
329336
| Expr::DateBetween { span, .. }
330337
| Expr::DateSub { span, .. }
331338
| Expr::DateTrunc { span, .. }
339+
| Expr::TimeSlice { span, .. }
332340
| Expr::LastDay { span, .. }
333341
| Expr::PreviousDay { span, .. }
334342
| Expr::NextDay { span, .. }
@@ -496,6 +504,7 @@ impl Expr {
496504
..
497505
} => merge_span(merge_span(*span, interval.whole_span()), date.whole_span()),
498506
Expr::DateTrunc { span, date, .. } => merge_span(*span, date.whole_span()),
507+
Expr::TimeSlice { span, date, .. } => merge_span(*span, date.whole_span()),
499508
Expr::LastDay { span, date, .. } => merge_span(*span, date.whole_span()),
500509
Expr::PreviousDay { span, date, .. } => merge_span(*span, date.whole_span()),
501510
Expr::NextDay { span, date, .. } => merge_span(*span, date.whole_span()),
@@ -870,6 +879,18 @@ impl Display for Expr {
870879
Expr::DateTrunc { unit, date, .. } => {
871880
write!(f, "DATE_TRUNC({unit}, {date})")?;
872881
}
882+
Expr::TimeSlice {
883+
unit,
884+
date,
885+
start_or_end,
886+
slice_length,
887+
..
888+
} => {
889+
write!(
890+
f,
891+
"TIME_SLICE({date}, {slice_length}, {unit}, '{start_or_end}')"
892+
)?;
893+
}
873894
Expr::LastDay { unit, date, .. } => {
874895
write!(f, "LAST_DAY({date}, {unit})")?;
875896
}

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ pub enum ExprElement {
329329
unit: IntervalKind,
330330
date: Expr,
331331
},
332+
TimeSlice {
333+
unit: IntervalKind,
334+
date: Expr,
335+
slice_length: u64,
336+
start_or_end: Option<String>,
337+
},
332338
LastDay {
333339
unit: IntervalKind,
334340
date: Expr,
@@ -458,6 +464,7 @@ impl ExprElement {
458464
ExprElement::DateBetween { .. } => Affix::Nilfix,
459465
ExprElement::DateSub { .. } => Affix::Nilfix,
460466
ExprElement::DateTrunc { .. } => Affix::Nilfix,
467+
ExprElement::TimeSlice { .. } => Affix::Nilfix,
461468
ExprElement::LastDay { .. } => Affix::Nilfix,
462469
ExprElement::PreviousDay { .. } => Affix::Nilfix,
463470
ExprElement::NextDay { .. } => Affix::Nilfix,
@@ -509,6 +516,7 @@ impl Expr {
509516
Expr::DateBetween { .. } => Affix::Nilfix,
510517
Expr::DateSub { .. } => Affix::Nilfix,
511518
Expr::DateTrunc { .. } => Affix::Nilfix,
519+
Expr::TimeSlice { .. } => Affix::Nilfix,
512520
Expr::LastDay { .. } => Affix::Nilfix,
513521
Expr::PreviousDay { .. } => Affix::Nilfix,
514522
Expr::NextDay { .. } => Affix::Nilfix,
@@ -724,6 +732,18 @@ impl<'a, I: Iterator<Item = WithSpan<'a, ExprElement>>> PrattParser<I> for ExprP
724732
unit,
725733
date: Box::new(date),
726734
},
735+
ExprElement::TimeSlice {
736+
unit,
737+
date,
738+
slice_length,
739+
start_or_end,
740+
} => Expr::TimeSlice {
741+
span: transform_span(elem.span.tokens),
742+
unit,
743+
date: Box::new(date),
744+
slice_length,
745+
start_or_end: start_or_end.unwrap_or("start".to_string()),
746+
},
727747
ExprElement::LastDay { unit, date } => Expr::LastDay {
728748
span: transform_span(elem.span.tokens),
729749
unit,
@@ -1329,6 +1349,18 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
13291349
|(_, _, unit, _, date, _)| ExprElement::DateTrunc { unit, date },
13301350
);
13311351

1352+
let time_slice = map(
1353+
rule! {
1354+
TIME_SLICE ~ "(" ~ #subexpr(0) ~ "," ~ ^#literal_u64 ~ "," ~ #interval_kind ~ ("," ~ ^#literal_string)? ~ ")"
1355+
},
1356+
|(_, _, date, _, slice_length, _, unit, opt_start_or_end, _)| ExprElement::TimeSlice {
1357+
unit,
1358+
date,
1359+
slice_length,
1360+
start_or_end: opt_start_or_end.map(|(_, start_or_end)| start_or_end),
1361+
},
1362+
);
1363+
13321364
let trunc = map(
13331365
rule! {
13341366
TRUNC ~ "(" ~ (#subexpr(0) ~ "," ~ #interval_kind)? ~ (#subexpr(0) ~ ("," ~ #subexpr(0))?)? ~ ")"
@@ -1482,6 +1514,7 @@ pub fn expr_element(i: Input) -> IResult<WithSpan<ExprElement>> {
14821514
| #date_sub : "`DATE_SUB(..., ..., (YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | SECOND | DOY | DOW))`"
14831515
| #date_between : "`DATE_BETWEEN((YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | SECOND | DOY | DOW), ..., ...,)`"
14841516
| #date_trunc : "`DATE_TRUNC((YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | SECOND | WEEK), ...)`"
1517+
| #time_slice : "`TIME_SLICE(<date_or_time_expr>, <slice_length>, (YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | SECOND | WEEK) [ , <start_or_end> ] )`"
14851518
| #trunc : "`TRUNC(..., (YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE | SECOND | WEEK))`"
14861519
| #last_day : "`LAST_DAY(..., (YEAR | QUARTER | MONTH | WEEK)))`"
14871520
| #previous_day : "`PREVIOUS_DAY(..., (Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday))`"

src/query/ast/src/parser/token.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ pub enum TokenKind {
521521
DATESUB,
522522
#[token("DATE_TRUNC", ignore(ascii_case))]
523523
DATE_TRUNC,
524+
#[token("TIME_SLICE", ignore(ascii_case))]
525+
TIME_SLICE,
524526
#[token("TRUNC", ignore(ascii_case))]
525527
TRUNC,
526528
#[token("DATETIME", ignore(ascii_case))]
@@ -1708,6 +1710,7 @@ impl TokenKind {
17081710
| TokenKind::DATE_SUB
17091711
| TokenKind::DATE_BETWEEN
17101712
| TokenKind::DATE_TRUNC
1713+
| TokenKind::TIME_SLICE
17111714
| TokenKind::TRUNC
17121715
| TokenKind::LAST_DAY
17131716
| TokenKind::PREVIOUS_DAY

src/query/ast/tests/it/parser.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,9 @@ fn test_expr() {
13121312
r#"date_part(year, d)"#,
13131313
r#"datepart(year, d)"#,
13141314
r#"date_trunc(week, to_timestamp(1630812366))"#,
1315+
r#"TIME_SLICE(to_timestamp(1630812366), 4, 'MONTH', 'START')"#,
1316+
r#"TIME_SLICE(to_timestamp(1630812366), 4, 'MONTH', 'end')"#,
1317+
r#"TIME_SLICE(to_timestamp(1630812366), 4, 'WEEK')"#,
13151318
r#"trunc(to_timestamp(1630812366), week)"#,
13161319
r#"trunc(1630812366, 999)"#,
13171320
r#"trunc(1630812366.23)"#,

src/query/ast/tests/it/testdata/expr-error.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ error:
5252
--> SQL:1:10
5353
|
5454
1 | CAST(col1)
55-
| ---- ^ unexpected `)`, expecting `AS`, `,`, `(`, `IS`, `NOT`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, or 47 more ...
55+
| ---- ^ unexpected `)`, expecting `AS`, `,`, `(`, `IS`, `NOT`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, or 48 more ...
5656
| |
5757
| while parsing `CAST(... AS ...)`
5858
| while parsing expression
@@ -81,7 +81,7 @@ error:
8181
1 | $ abc + 3
8282
| ^
8383
| |
84-
| unexpected `$`, expecting `IS`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `NOT`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, `IdentVariable`, `DATEADD`, `DATE_ADD`, or 45 more ...
84+
| unexpected `$`, expecting `IS`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `NOT`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, `IdentVariable`, `DATEADD`, `DATE_ADD`, or 46 more ...
8585
| while parsing expression
8686

8787

src/query/ast/tests/it/testdata/expr.txt

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,141 @@ DateTrunc {
18851885
}
18861886

18871887

1888+
---------- Input ----------
1889+
TIME_SLICE(to_timestamp(1630812366), 4, 'MONTH', 'START')
1890+
---------- Output ---------
1891+
TIME_SLICE(to_timestamp(1630812366), 4, MONTH, 'START')
1892+
---------- AST ------------
1893+
TimeSlice {
1894+
span: Some(
1895+
0..57,
1896+
),
1897+
date: FunctionCall {
1898+
span: Some(
1899+
11..35,
1900+
),
1901+
func: FunctionCall {
1902+
distinct: false,
1903+
name: Identifier {
1904+
span: Some(
1905+
11..23,
1906+
),
1907+
name: "to_timestamp",
1908+
quote: None,
1909+
ident_type: None,
1910+
},
1911+
args: [
1912+
Literal {
1913+
span: Some(
1914+
24..34,
1915+
),
1916+
value: UInt64(
1917+
1630812366,
1918+
),
1919+
},
1920+
],
1921+
params: [],
1922+
order_by: [],
1923+
window: None,
1924+
lambda: None,
1925+
},
1926+
},
1927+
slice_length: 4,
1928+
unit: Month,
1929+
start_or_end: "START",
1930+
}
1931+
1932+
1933+
---------- Input ----------
1934+
TIME_SLICE(to_timestamp(1630812366), 4, 'MONTH', 'end')
1935+
---------- Output ---------
1936+
TIME_SLICE(to_timestamp(1630812366), 4, MONTH, 'end')
1937+
---------- AST ------------
1938+
TimeSlice {
1939+
span: Some(
1940+
0..55,
1941+
),
1942+
date: FunctionCall {
1943+
span: Some(
1944+
11..35,
1945+
),
1946+
func: FunctionCall {
1947+
distinct: false,
1948+
name: Identifier {
1949+
span: Some(
1950+
11..23,
1951+
),
1952+
name: "to_timestamp",
1953+
quote: None,
1954+
ident_type: None,
1955+
},
1956+
args: [
1957+
Literal {
1958+
span: Some(
1959+
24..34,
1960+
),
1961+
value: UInt64(
1962+
1630812366,
1963+
),
1964+
},
1965+
],
1966+
params: [],
1967+
order_by: [],
1968+
window: None,
1969+
lambda: None,
1970+
},
1971+
},
1972+
slice_length: 4,
1973+
unit: Month,
1974+
start_or_end: "end",
1975+
}
1976+
1977+
1978+
---------- Input ----------
1979+
TIME_SLICE(to_timestamp(1630812366), 4, 'WEEK')
1980+
---------- Output ---------
1981+
TIME_SLICE(to_timestamp(1630812366), 4, WEEK, 'start')
1982+
---------- AST ------------
1983+
TimeSlice {
1984+
span: Some(
1985+
0..47,
1986+
),
1987+
date: FunctionCall {
1988+
span: Some(
1989+
11..35,
1990+
),
1991+
func: FunctionCall {
1992+
distinct: false,
1993+
name: Identifier {
1994+
span: Some(
1995+
11..23,
1996+
),
1997+
name: "to_timestamp",
1998+
quote: None,
1999+
ident_type: None,
2000+
},
2001+
args: [
2002+
Literal {
2003+
span: Some(
2004+
24..34,
2005+
),
2006+
value: UInt64(
2007+
1630812366,
2008+
),
2009+
},
2010+
],
2011+
params: [],
2012+
order_by: [],
2013+
window: None,
2014+
lambda: None,
2015+
},
2016+
},
2017+
slice_length: 4,
2018+
unit: Week,
2019+
start_or_end: "start",
2020+
}
2021+
2022+
18882023
---------- Input ----------
18892024
trunc(to_timestamp(1630812366), week)
18902025
---------- Output ---------

src/query/ast/tests/it/testdata/stmt-error.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ error:
556556
--> SQL:1:41
557557
|
558558
1 | SELECT * FROM t GROUP BY GROUPING SETS ()
559-
| ------ ^ unexpected `)`, expecting `(`, `IS`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `NOT`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, `IdentVariable`, `DATEADD`, or 45 more ...
559+
| ------ ^ unexpected `)`, expecting `(`, `IS`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `NOT`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, `TRY_CAST`, `::`, `POSITION`, `IdentVariable`, `DATEADD`, or 46 more ...
560560
| |
561561
| while parsing `SELECT ...`
562562

@@ -978,7 +978,7 @@ error:
978978
--> SQL:1:65
979979
|
980980
1 | CREATE FUNCTION IF NOT EXISTS isnotempty AS(p) -> not(is_null(p)
981-
| ------ -- ---- ^ unexpected end of input, expecting `)`, `(`, `WITHIN`, `IGNORE`, `RESPECT`, `OVER`, `IS`, `NOT`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, or 51 more ...
981+
| ------ -- ---- ^ unexpected end of input, expecting `)`, `(`, `WITHIN`, `IGNORE`, `RESPECT`, `OVER`, `IS`, `NOT`, `IN`, `LIKE`, `EXISTS`, `BETWEEN`, `+`, `-`, `*`, `/`, `//`, `DIV`, `%`, `||`, `<=>`, `<+>`, `<->`, `>`, `<`, `>=`, `<=`, `=`, `<>`, `!=`, `^`, `AND`, `OR`, `XOR`, `REGEXP`, `RLIKE`, `SOUNDS`, <BitWiseOr>, <BitWiseAnd>, <BitWiseXor>, <ShiftLeft>, <ShiftRight>, `->`, `->>`, `#>`, `#>>`, `?`, `?|`, `?&`, `@>`, `<@`, `@?`, `@@`, `#-`, <Factorial>, <SquareRoot>, <BitWiseNot>, <CubeRoot>, <Abs>, `CAST`, or 52 more ...
982982
| | | | |
983983
| | | | while parsing `(<expr> [, ...])`
984984
| | | while parsing expression

0 commit comments

Comments
 (0)