Skip to content

Commit 07bdfc5

Browse files
committed
feat(query): Allow extract parts from interval type
1 parent c5c7fce commit 07bdfc5

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-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/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)