Skip to content

Commit 3c1c34d

Browse files
authored
feat(query): Allow extract parts from interval type (#17417)
1 parent b98ad71 commit 3c1c34d

File tree

7 files changed

+147
-0
lines changed

7 files changed

+147
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,7 @@ pub enum IntervalKind {
829829
Week,
830830
Dow,
831831
Epoch,
832+
MicroSecond,
832833
}
833834

834835
impl Display for IntervalKind {
@@ -845,6 +846,7 @@ impl Display for IntervalKind {
845846
IntervalKind::Dow => "DOW",
846847
IntervalKind::Week => "WEEK",
847848
IntervalKind::Epoch => "EPOCH",
849+
IntervalKind::MicroSecond => "MICROSECOND",
848850
})
849851
}
850852
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,7 @@ pub fn interval_kind(i: Input) -> IResult<IntervalKind> {
18431843
let dow = value(IntervalKind::Dow, rule! { DOW });
18441844
let week = value(IntervalKind::Week, rule! { WEEK });
18451845
let epoch = value(IntervalKind::Epoch, rule! { EPOCH });
1846+
let microsecond = value(IntervalKind::MicroSecond, rule! { MICROSECOND });
18461847
let year_str = value(
18471848
IntervalKind::Year,
18481849
rule! { #literal_string_eq_ignore_case("YEAR") },
@@ -1887,6 +1888,10 @@ pub fn interval_kind(i: Input) -> IResult<IntervalKind> {
18871888
IntervalKind::Epoch,
18881889
rule! { #literal_string_eq_ignore_case("EPOCH") },
18891890
);
1891+
let microsecond_str = value(
1892+
IntervalKind::MicroSecond,
1893+
rule! { #literal_string_eq_ignore_case("MICROSECOND") },
1894+
);
18901895
alt((
18911896
rule!(
18921897
#year
@@ -1900,6 +1905,7 @@ pub fn interval_kind(i: Input) -> IResult<IntervalKind> {
19001905
| #dow
19011906
| #week
19021907
| #epoch
1908+
| #microsecond
19031909
),
19041910
rule!(
19051911
#year_str
@@ -1913,6 +1919,7 @@ pub fn interval_kind(i: Input) -> IResult<IntervalKind> {
19131919
| #dow_str
19141920
| #week_str
19151921
| #epoch_str
1922+
| #microsecond_str
19161923
),
19171924
))(i)
19181925
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ pub enum TokenKind {
583583
ENGINES,
584584
#[token("EPOCH", ignore(ascii_case))]
585585
EPOCH,
586+
#[token("MICROSECOND", ignore(ascii_case))]
587+
MICROSECOND,
586588
#[token("ERROR_ON_COLUMN_COUNT_MISMATCH", ignore(ascii_case))]
587589
ERROR_ON_COLUMN_COUNT_MISMATCH,
588590
#[token("ESCAPE", ignore(ascii_case))]

src/query/functions/src/scalars/timestamp/src/interval.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use databend_common_expression::date_helper::EvalMonthsImpl;
1919
use databend_common_expression::error_to_null;
2020
use databend_common_expression::types::interval::interval_to_string;
2121
use databend_common_expression::types::interval::string_to_interval;
22+
use databend_common_expression::types::Float64Type;
2223
use databend_common_expression::types::Int64Type;
2324
use databend_common_expression::types::IntervalType;
2425
use databend_common_expression::types::StringType;
@@ -296,4 +297,72 @@ fn register_number_to_interval(registry: &mut FunctionRegistry) {
296297
output.push(res);
297298
}),
298299
);
300+
301+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
302+
"to_year",
303+
|_, _| FunctionDomain::MayThrow,
304+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
305+
output.push(val.months() as i64 / 12);
306+
}),
307+
);
308+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
309+
"to_month",
310+
|_, _| FunctionDomain::MayThrow,
311+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
312+
output.push(val.months() as i64);
313+
}),
314+
);
315+
// Directly return interval days. Extract need named to_day_of_month
316+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
317+
"to_day_of_month",
318+
|_, _| FunctionDomain::MayThrow,
319+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
320+
output.push(val.days() as i64);
321+
}),
322+
);
323+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
324+
"to_hour",
325+
|_, _| FunctionDomain::MayThrow,
326+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
327+
let total_seconds = (val.microseconds() as f64) / 1_000_000.0;
328+
let hours = (total_seconds / 3600.0) as i64;
329+
output.push(hours);
330+
}),
331+
);
332+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
333+
"to_minute",
334+
|_, _| FunctionDomain::MayThrow,
335+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
336+
let total_seconds = (val.microseconds() as f64) / 1_000_000.0;
337+
let minutes = ((total_seconds % 3600.0) / 60.0) as i64;
338+
output.push(minutes);
339+
}),
340+
);
341+
342+
registry.register_passthrough_nullable_1_arg::<IntervalType, Float64Type, _, _>(
343+
"to_second",
344+
|_, _| FunctionDomain::MayThrow,
345+
vectorize_with_builder_1_arg::<IntervalType, Float64Type>(|val, output, _| {
346+
let microseconds = val.microseconds() % 60_000_000;
347+
let seconds = microseconds as f64 / 1_000_000.0;
348+
output.push(seconds.into());
349+
}),
350+
);
351+
352+
registry.register_passthrough_nullable_1_arg::<IntervalType, Int64Type, _, _>(
353+
"to_microsecond",
354+
|_, _| FunctionDomain::MayThrow,
355+
vectorize_with_builder_1_arg::<IntervalType, Int64Type>(|val, output, _| {
356+
let microseconds = val.microseconds() % 60_000_000;
357+
output.push(microseconds);
358+
}),
359+
);
360+
registry.register_passthrough_nullable_1_arg::<IntervalType, Float64Type, _, _>(
361+
"epoch",
362+
|_, _| FunctionDomain::MayThrow,
363+
vectorize_with_builder_1_arg::<IntervalType, Float64Type>(|val, output, _| {
364+
let total_seconds = (val.total_micros() as f64) / 1_000_000.0;
365+
output.push(total_seconds.into());
366+
}),
367+
);
299368
}

src/query/functions/tests/it/scalars/testdata/function_list.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,8 @@ Functions overloads:
16751675
1 epoch(Timestamp NULL) :: Float64 NULL
16761676
2 epoch(Int64) :: Interval
16771677
3 epoch(Int64 NULL) :: Interval NULL
1678+
4 epoch(Interval) :: Float64
1679+
5 epoch(Interval NULL) :: Float64 NULL
16781680
0 eq(Variant, Variant) :: Boolean
16791681
1 eq(Variant NULL, Variant NULL) :: Boolean NULL
16801682
2 eq(String, String) :: Boolean
@@ -3558,6 +3560,8 @@ Functions overloads:
35583560
1 to_day_of_month(Date NULL) :: UInt8 NULL
35593561
2 to_day_of_month(Timestamp) :: UInt8
35603562
3 to_day_of_month(Timestamp NULL) :: UInt8 NULL
3563+
4 to_day_of_month(Interval) :: Int64
3564+
5 to_day_of_month(Interval NULL) :: Int64 NULL
35613565
0 to_day_of_week(Date) :: UInt8
35623566
1 to_day_of_week(Date NULL) :: UInt8 NULL
35633567
2 to_day_of_week(Timestamp) :: UInt8
@@ -3644,6 +3648,8 @@ Functions overloads:
36443648
5 to_hex(Binary NULL) :: String NULL
36453649
0 to_hour(Timestamp) :: UInt8
36463650
1 to_hour(Timestamp NULL) :: UInt8 NULL
3651+
2 to_hour(Interval) :: Int64
3652+
3 to_hour(Interval NULL) :: Int64 NULL
36473653
0 to_hours(Int64) :: Interval
36483654
1 to_hours(Int64 NULL) :: Interval NULL
36493655
0 to_int16(Variant) :: Int16
@@ -3772,6 +3778,8 @@ Functions overloads:
37723778
1 to_last_of_year(Date NULL) :: Date NULL
37733779
2 to_last_of_year(Timestamp) :: Date
37743780
3 to_last_of_year(Timestamp NULL) :: Date NULL
3781+
0 to_microsecond(Interval) :: Int64
3782+
1 to_microsecond(Interval NULL) :: Int64 NULL
37753783
0 to_microseconds(Int64) :: Interval
37763784
1 to_microseconds(Int64 NULL) :: Interval NULL
37773785
0 to_millennia(Int64) :: Interval
@@ -3780,6 +3788,8 @@ Functions overloads:
37803788
1 to_milliseconds(Int64 NULL) :: Interval NULL
37813789
0 to_minute(Timestamp) :: UInt8
37823790
1 to_minute(Timestamp NULL) :: UInt8 NULL
3791+
2 to_minute(Interval) :: Int64
3792+
3 to_minute(Interval NULL) :: Int64 NULL
37833793
0 to_minutes(Int64) :: Interval
37843794
1 to_minutes(Int64 NULL) :: Interval NULL
37853795
0 to_monday(Date) :: Date
@@ -3790,6 +3800,8 @@ Functions overloads:
37903800
1 to_month(Date NULL) :: UInt8 NULL
37913801
2 to_month(Timestamp) :: UInt8
37923802
3 to_month(Timestamp NULL) :: UInt8 NULL
3803+
4 to_month(Interval) :: Int64
3804+
5 to_month(Interval NULL) :: Int64 NULL
37933805
0 to_months(Int64) :: Interval
37943806
1 to_months(Int64 NULL) :: Interval NULL
37953807
0 to_next_friday(Date) :: Date
@@ -3856,6 +3868,8 @@ Functions overloads:
38563868
3 to_quarter(Timestamp NULL) :: UInt8 NULL
38573869
0 to_second(Timestamp) :: UInt8
38583870
1 to_second(Timestamp NULL) :: UInt8 NULL
3871+
2 to_second(Interval) :: Float64
3872+
3 to_second(Interval NULL) :: Float64 NULL
38593873
0 to_seconds(Int64) :: Interval
38603874
1 to_seconds(Int64 NULL) :: Interval NULL
38613875
0 to_start_of_day(Timestamp) :: Timestamp
@@ -4066,6 +4080,8 @@ Functions overloads:
40664080
1 to_year(Date NULL) :: UInt16 NULL
40674081
2 to_year(Timestamp) :: UInt16
40684082
3 to_year(Timestamp NULL) :: UInt16 NULL
4083+
4 to_year(Interval) :: Int64
4084+
5 to_year(Interval NULL) :: Int64 NULL
40694085
0 to_years(Int64) :: Interval
40704086
1 to_years(Int64 NULL) :: Interval NULL
40714087
0 to_yyyymm(Date) :: UInt32

src/query/sql/src/planner/semantic/type_check.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,6 +2950,9 @@ impl<'a> TypeChecker<'a> {
29502950
ASTIntervalKind::Dow => self.resolve_function(span, "to_day_of_week", vec![], &[arg]),
29512951
ASTIntervalKind::Week => self.resolve_function(span, "to_week_of_year", vec![], &[arg]),
29522952
ASTIntervalKind::Epoch => self.resolve_function(span, "epoch", vec![], &[arg]),
2953+
ASTIntervalKind::MicroSecond => {
2954+
self.resolve_function(span, "to_microsecond", vec![], &[arg])
2955+
}
29532956
}
29542957
}
29552958

tests/sqllogictests/suites/base/11_data_type/11_0007_data_type_interval.test

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,51 @@ select sum(c) from t where c <= interval '1 day';
4141

4242
statement ok
4343
drop table t;
44+
45+
onlyif http
46+
query T
47+
select EXTRACT(epoch from '1 day 2 hours 3 minutes'::INTERVAL);
48+
----
49+
93780.0
50+
51+
onlyif http
52+
query T
53+
select EXTRACT(minute from '1 day 2 hours 3 minutes'::INTERVAL);
54+
----
55+
3
56+
57+
onlyif http
58+
query T
59+
select EXTRACT(hour from '1 day 48 hours 3600 minutes'::INTERVAL);
60+
----
61+
108
62+
63+
onlyif http
64+
query T
65+
select EXTRACT(day from '1 day 48 hours 3600 minutes'::INTERVAL);
66+
----
67+
1
68+
69+
onlyif http
70+
query T
71+
select EXTRACT(second from '1 day 2 hours 3 minutes 200 seconds 100 microsecond'::INTERVAL);
72+
----
73+
20.0001
74+
75+
onlyif http
76+
query T
77+
select EXTRACT(microsecond from '1 day 2 hours 3 minutes 200 seconds 100 microsecond'::INTERVAL);
78+
----
79+
20000100
80+
81+
onlyif http
82+
query T
83+
select EXTRACT(month from '3 months 60 day 2 hours 3 minutes 200 seconds 100 microsecond'::INTERVAL);
84+
----
85+
3
86+
87+
onlyif http
88+
query T
89+
select EXTRACT(year from '1 years 13 months 60 day 2 hours 3 minutes 200 seconds 100 microsecond'::INTERVAL);
90+
----
91+
2

0 commit comments

Comments
 (0)