Skip to content

Commit e76aabc

Browse files
authored
feat(query): support extract EPOCH from timestamp (#17385)
* feat(query): support extract EPOCH from timestamp * use val directly * add domain * function rename to epoch
1 parent c2e462e commit e76aabc

File tree

7 files changed

+132
-51
lines changed

7 files changed

+132
-51
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ pub enum IntervalKind {
828828
Doy,
829829
Week,
830830
Dow,
831+
Epoch,
831832
}
832833

833834
impl Display for IntervalKind {
@@ -843,6 +844,7 @@ impl Display for IntervalKind {
843844
IntervalKind::Doy => "DOY",
844845
IntervalKind::Dow => "DOW",
845846
IntervalKind::Week => "WEEK",
847+
IntervalKind::Epoch => "EPOCH",
846848
})
847849
}
848850
}

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

Lines changed: 79 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,56 +1821,87 @@ pub fn weekday(i: Input) -> IResult<Weekday> {
18211821
}
18221822

18231823
pub fn interval_kind(i: Input) -> IResult<IntervalKind> {
1824+
let year = value(IntervalKind::Year, rule! { YEAR });
1825+
let quarter = value(IntervalKind::Quarter, rule! { QUARTER });
1826+
let month = value(IntervalKind::Month, rule! { MONTH });
1827+
let day = value(IntervalKind::Day, rule! { DAY });
1828+
let hour = value(IntervalKind::Hour, rule! { HOUR });
1829+
let minute = value(IntervalKind::Minute, rule! { MINUTE });
1830+
let second = value(IntervalKind::Second, rule! { SECOND });
1831+
let doy = value(IntervalKind::Doy, rule! { DOY });
1832+
let dow = value(IntervalKind::Dow, rule! { DOW });
1833+
let week = value(IntervalKind::Week, rule! { WEEK });
1834+
let epoch = value(IntervalKind::Epoch, rule! { EPOCH });
1835+
let year_str = value(
1836+
IntervalKind::Year,
1837+
rule! { #literal_string_eq_ignore_case("YEAR") },
1838+
);
1839+
let quarter_str = value(
1840+
IntervalKind::Quarter,
1841+
rule! { #literal_string_eq_ignore_case("QUARTER") },
1842+
);
1843+
let month_str = value(
1844+
IntervalKind::Month,
1845+
rule! { #literal_string_eq_ignore_case("MONTH") },
1846+
);
1847+
let day_str = value(
1848+
IntervalKind::Day,
1849+
rule! { #literal_string_eq_ignore_case("DAY") },
1850+
);
1851+
let hour_str = value(
1852+
IntervalKind::Hour,
1853+
rule! { #literal_string_eq_ignore_case("HOUR") },
1854+
);
1855+
let minute_str = value(
1856+
IntervalKind::Minute,
1857+
rule! { #literal_string_eq_ignore_case("MINUTE") },
1858+
);
1859+
let second_str = value(
1860+
IntervalKind::Second,
1861+
rule! { #literal_string_eq_ignore_case("SECOND") },
1862+
);
1863+
let doy_str = value(
1864+
IntervalKind::Doy,
1865+
rule! { #literal_string_eq_ignore_case("DOY") },
1866+
);
1867+
let dow_str = value(
1868+
IntervalKind::Dow,
1869+
rule! { #literal_string_eq_ignore_case("DOW") },
1870+
);
1871+
let week_str = value(
1872+
IntervalKind::Week,
1873+
rule! { #literal_string_eq_ignore_case("WEEK") },
1874+
);
1875+
let epoch_str = value(
1876+
IntervalKind::Epoch,
1877+
rule! { #literal_string_eq_ignore_case("EPOCH") },
1878+
);
18241879
alt((
1825-
value(IntervalKind::Year, rule! { YEAR }),
1826-
value(IntervalKind::Quarter, rule! { QUARTER }),
1827-
value(IntervalKind::Month, rule! { MONTH }),
1828-
value(IntervalKind::Day, rule! { DAY }),
1829-
value(IntervalKind::Hour, rule! { HOUR }),
1830-
value(IntervalKind::Minute, rule! { MINUTE }),
1831-
value(IntervalKind::Second, rule! { SECOND }),
1832-
value(IntervalKind::Doy, rule! { DOY }),
1833-
value(IntervalKind::Dow, rule! { DOW }),
1834-
value(IntervalKind::Week, rule! { WEEK }),
1835-
value(
1836-
IntervalKind::Year,
1837-
rule! { #literal_string_eq_ignore_case("YEAR") },
1880+
rule!(
1881+
#year
1882+
| #quarter
1883+
| #month
1884+
| #day
1885+
| #hour
1886+
| #minute
1887+
| #second
1888+
| #doy
1889+
| #dow
1890+
| #week
1891+
| #epoch
18381892
),
1839-
value(
1840-
IntervalKind::Quarter,
1841-
rule! { #literal_string_eq_ignore_case("QUARTER") },
1842-
),
1843-
value(
1844-
IntervalKind::Month,
1845-
rule! { #literal_string_eq_ignore_case("MONTH") },
1846-
),
1847-
value(
1848-
IntervalKind::Day,
1849-
rule! { #literal_string_eq_ignore_case("DAY") },
1850-
),
1851-
value(
1852-
IntervalKind::Hour,
1853-
rule! { #literal_string_eq_ignore_case("HOUR") },
1854-
),
1855-
value(
1856-
IntervalKind::Minute,
1857-
rule! { #literal_string_eq_ignore_case("MINUTE") },
1858-
),
1859-
value(
1860-
IntervalKind::Second,
1861-
rule! { #literal_string_eq_ignore_case("SECOND") },
1862-
),
1863-
value(
1864-
IntervalKind::Doy,
1865-
rule! { #literal_string_eq_ignore_case("DOY") },
1866-
),
1867-
value(
1868-
IntervalKind::Dow,
1869-
rule! { #literal_string_eq_ignore_case("DOW") },
1870-
),
1871-
value(
1872-
IntervalKind::Week,
1873-
rule! { #literal_string_eq_ignore_case("WEEK") },
1893+
rule!(
1894+
#year_str
1895+
| #quarter_str
1896+
| #month_str
1897+
| #day_str
1898+
| #hour_str
1899+
| #minute_str
1900+
| #second_str
1901+
| #doy_str
1902+
| #dow_str
1903+
| #week_str
1904+
| #epoch_str
18741905
),
18751906
))(i)
18761907
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,17 @@ fn register_to_number_functions(registry: &mut FunctionRegistry) {
15241524
}),
15251525
);
15261526

1527+
registry.register_passthrough_nullable_1_arg::<TimestampType, Float64Type, _, _>(
1528+
"epoch",
1529+
|_, domain| {
1530+
FunctionDomain::Domain(SimpleDomain::<F64> {
1531+
min: (domain.min as f64 / 1_000_000f64).into(),
1532+
max: (domain.max as f64 / 1_000_000f64).into(),
1533+
})
1534+
},
1535+
vectorize_1_arg::<TimestampType, Float64Type>(|val, _| (val as f64 / 1_000_000f64).into()),
1536+
);
1537+
15271538
registry.register_passthrough_nullable_1_arg::<TimestampType, UInt8Type, _, _>(
15281539
"to_hour",
15291540
|_, _| FunctionDomain::Full,

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,8 +1671,10 @@ Functions overloads:
16711671
199 divide(Float64, Float64) :: Float64
16721672
200 divide(Float64 NULL, Float64 NULL) :: Float64 NULL
16731673
0 divnull(Float64 NULL, Float64 NULL) :: Float64 NULL
1674-
0 epoch(Int64) :: Interval
1675-
1 epoch(Int64 NULL) :: Interval NULL
1674+
0 epoch(Timestamp) :: Float64
1675+
1 epoch(Timestamp NULL) :: Float64 NULL
1676+
2 epoch(Int64) :: Interval
1677+
3 epoch(Int64 NULL) :: Interval NULL
16761678
0 eq(Variant, Variant) :: Boolean
16771679
1 eq(Variant NULL, Variant NULL) :: Boolean NULL
16781680
2 eq(String, String) :: Boolean

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2930,6 +2930,7 @@ impl<'a> TypeChecker<'a> {
29302930
ASTIntervalKind::Doy => self.resolve_function(span, "to_day_of_year", vec![], &[arg]),
29312931
ASTIntervalKind::Dow => self.resolve_function(span, "to_day_of_week", vec![], &[arg]),
29322932
ASTIntervalKind::Week => self.resolve_function(span, "to_week_of_year", vec![], &[arg]),
2933+
ASTIntervalKind::Epoch => self.resolve_function(span, "epoch", vec![], &[arg]),
29332934
}
29342935
}
29352936

src/tests/sqlsmith/src/sql_gen/expr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ impl<R: Rng> SqlGenerator<'_, R> {
495495
DataType::Timestamp
496496
};
497497
let expr = self.gen_expr(&expr_ty);
498-
let kind = match self.rng.gen_range(0..=9) {
498+
let kind = match self.rng.gen_range(0..=10) {
499499
0 => IntervalKind::Year,
500500
1 => IntervalKind::Quarter,
501501
2 => IntervalKind::Month,
@@ -506,6 +506,7 @@ impl<R: Rng> SqlGenerator<'_, R> {
506506
7 => IntervalKind::Doy,
507507
8 => IntervalKind::Dow,
508508
9 => IntervalKind::Week,
509+
10 => IntervalKind::Epoch,
509510
_ => unreachable!(),
510511
};
511512
Expr::Extract {

tests/sqllogictests/suites/query/functions/02_0012_function_datetimes.test

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,40 @@ select EXTRACT(YEAR FROM to_datetime('2022-03-04 22:32:09')) = 2022
11241124
----
11251125
1
11261126

1127+
query T
1128+
select EXTRACT(EPOCH FROM to_datetime('1969-12-31 23:59:59'))
1129+
----
1130+
-1.0
1131+
1132+
statement ok
1133+
create or replace table t_epoch(c timestamp);
1134+
1135+
statement ok
1136+
insert into t_epoch values('1969-12-31 23:59:59'), ('1970-01-01 00:00:01.123456789');
1137+
1138+
query T
1139+
select EXTRACT(EPOCH FROM c) from t_epoch order by c;
1140+
----
1141+
-1.0
1142+
1.123456
1143+
1144+
statement ok
1145+
drop table if exists t_epoch;
11271146

1147+
query T
1148+
select EXTRACT(EPOCH FROM to_datetime('1969-12-31 23:59:59.999999'))
1149+
----
1150+
-1.0e-6
1151+
1152+
query B
1153+
select EXTRACT(EPOCH FROM now()) = epoch(now())
1154+
----
1155+
1
1156+
1157+
query B
1158+
SELECT (to_timestamp('2023-11-12 09:38:18.965575') - to_timestamp(0)) / 1000000.0 = epoch('2023-11-12 09:38:18.965575')
1159+
----
1160+
1
11281161

11291162
query B
11301163
select EXTRACT(MONTH FROM to_datetime('2022-03-04 22:32:09')) = 3

0 commit comments

Comments
 (0)