Skip to content

Commit

Permalink
[Enhancement] Extend interval type for 'date_trunc', 'days_add', 'tim…
Browse files Browse the repository at this point in the history
…e_slice' (StarRocks#36386)

Signed-off-by: liuyehcf <[email protected]>
  • Loading branch information
liuyehcf authored Dec 5, 2023
1 parent a495825 commit 1a00830
Show file tree
Hide file tree
Showing 12 changed files with 510 additions and 9 deletions.
46 changes: 40 additions & 6 deletions be/src/exprs/time_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,11 @@ Status TimeFunctions::time_slice_prepare(FunctionContext* context, FunctionConte
if (boundary->type == LogicalType::TYPE_DATETIME) {
// floor specify START as the result time.
if (time_base == "floor") {
if (period_unit == "second") {
if (period_unit == "microsecond") {
function = &TimeFunctions::time_slice_datetime_start_microsecond;
} else if (period_unit == "millisecond") {
function = &TimeFunctions::time_slice_datetime_start_millisecond;
} else if (period_unit == "second") {
function = &TimeFunctions::time_slice_datetime_start_second;
} else if (period_unit == "minute") {
function = &TimeFunctions::time_slice_datetime_start_minute;
Expand All @@ -904,12 +908,17 @@ Status TimeFunctions::time_slice_prepare(FunctionContext* context, FunctionConte
function = &TimeFunctions::time_slice_datetime_start_quarter;
} else {
return Status::InternalError(
"period unit must in {second, minute, hour, day, month, year, week, quarter}");
"period unit must in {microsecond, millisecond, second, minute, hour, day, month, year, week, "
"quarter}");
}
} else {
// ceil specify END as the result time.
DCHECK_EQ(time_base, "ceil");
if (period_unit == "second") {
if (period_unit == "microsecond") {
function = &TimeFunctions::time_slice_datetime_end_microsecond;
} else if (period_unit == "millisecond") {
function = &TimeFunctions::time_slice_datetime_end_millisecond;
} else if (period_unit == "second") {
function = &TimeFunctions::time_slice_datetime_end_second;
} else if (period_unit == "minute") {
function = &TimeFunctions::time_slice_datetime_end_minute;
Expand All @@ -927,7 +936,8 @@ Status TimeFunctions::time_slice_prepare(FunctionContext* context, FunctionConte
function = &TimeFunctions::time_slice_datetime_end_quarter;
} else {
return Status::InternalError(
"period unit must in {second, minute, hour, day, month, year, week, quarter}");
"period unit must in {microsecond, millisecond, second, minute, hour, day, month, year, week, "
"quarter}");
}
}
} else {
Expand Down Expand Up @@ -1011,6 +1021,12 @@ Status TimeFunctions::time_slice_prepare(FunctionContext* context, FunctionConte
DEFINE_TIME_SLICE_FN_CALL(datetime, UNIT, TYPE_DATETIME, TYPE_INT, TYPE_DATETIME); \
DEFINE_TIME_SLICE_FN_CALL(date, UNIT, TYPE_DATE, TYPE_INT, TYPE_DATE);

// time_slice_to_second
DEFINE_TIME_SLICE_FN(microsecond);

// time_slice_to_second
DEFINE_TIME_SLICE_FN(millisecond);

// time_slice_to_second
DEFINE_TIME_SLICE_FN(second);

Expand Down Expand Up @@ -2455,7 +2471,11 @@ Status TimeFunctions::datetime_trunc_prepare(FunctionContext* context, FunctionC
[](unsigned char c) { return std::tolower(c); });

ScalarFunction function;
if (format_value == "second") {
if (format_value == "microsecond") {
function = &TimeFunctions::datetime_trunc_microsecond;
} else if (format_value == "millisecond") {
function = &TimeFunctions::datetime_trunc_millisecond;
} else if (format_value == "second") {
function = &TimeFunctions::datetime_trunc_second;
} else if (format_value == "minute") {
function = &TimeFunctions::datetime_trunc_minute;
Expand All @@ -2472,7 +2492,9 @@ Status TimeFunctions::datetime_trunc_prepare(FunctionContext* context, FunctionC
} else if (format_value == "quarter") {
function = &TimeFunctions::datetime_trunc_quarter;
} else {
return Status::InternalError("format value must in {second, minute, hour, day, month, year, week, quarter}");
return Status::InternalError(
"format value must in {microsecond, millisecond, second, minute, hour, day, month, year, week, "
"quarter}");
}

auto fc = new DateTruncCtx();
Expand All @@ -2481,6 +2503,18 @@ Status TimeFunctions::datetime_trunc_prepare(FunctionContext* context, FunctionC
return Status::OK();
}

DEFINE_UNARY_FN_WITH_IMPL(datetime_trunc_microsecondImpl, v) {
return v;
}
DEFINE_TIME_UNARY_FN_EXTEND(datetime_trunc_microsecond, TYPE_DATETIME, TYPE_DATETIME, 1);

DEFINE_UNARY_FN_WITH_IMPL(datetime_trunc_millisecondImpl, v) {
TimestampValue result = v;
result.trunc_to_millisecond();
return result;
}
DEFINE_TIME_UNARY_FN_EXTEND(datetime_trunc_millisecond, TYPE_DATETIME, TYPE_DATETIME, 1);

DEFINE_UNARY_FN_WITH_IMPL(datetime_trunc_secondImpl, v) {
TimestampValue result = v;
result.trunc_to_second();
Expand Down
12 changes: 11 additions & 1 deletion be/src/exprs/time_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ class TimeFunctions {
* Called by datetime_trunc
* Truncate to the corresponding part
*/
DEFINE_VECTORIZED_FN(datetime_trunc_microsecond);
DEFINE_VECTORIZED_FN(datetime_trunc_millisecond);
DEFINE_VECTORIZED_FN(datetime_trunc_second);
DEFINE_VECTORIZED_FN(datetime_trunc_minute);
DEFINE_VECTORIZED_FN(datetime_trunc_hour);
Expand All @@ -265,6 +267,8 @@ class TimeFunctions {
* Called by time_slice
* Floor to the corresponding period
*/
DEFINE_VECTORIZED_FN(time_slice_datetime_start_microsecond);
DEFINE_VECTORIZED_FN(time_slice_datetime_start_millisecond);
DEFINE_VECTORIZED_FN(time_slice_datetime_start_second);
DEFINE_VECTORIZED_FN(time_slice_datetime_start_minute);
DEFINE_VECTORIZED_FN(time_slice_datetime_start_hour);
Expand All @@ -274,6 +278,8 @@ class TimeFunctions {
DEFINE_VECTORIZED_FN(time_slice_datetime_start_week);
DEFINE_VECTORIZED_FN(time_slice_datetime_start_quarter);

DEFINE_VECTORIZED_FN(time_slice_datetime_end_microsecond);
DEFINE_VECTORIZED_FN(time_slice_datetime_end_millisecond);
DEFINE_VECTORIZED_FN(time_slice_datetime_end_second);
DEFINE_VECTORIZED_FN(time_slice_datetime_end_minute);
DEFINE_VECTORIZED_FN(time_slice_datetime_end_hour);
Expand All @@ -283,6 +289,8 @@ class TimeFunctions {
DEFINE_VECTORIZED_FN(time_slice_datetime_end_week);
DEFINE_VECTORIZED_FN(time_slice_datetime_end_quarter);

DEFINE_VECTORIZED_FN(time_slice_date_start_microsecond);
DEFINE_VECTORIZED_FN(time_slice_date_start_millisecond);
DEFINE_VECTORIZED_FN(time_slice_date_start_second);
DEFINE_VECTORIZED_FN(time_slice_date_start_minute);
DEFINE_VECTORIZED_FN(time_slice_date_start_hour);
Expand All @@ -292,6 +300,8 @@ class TimeFunctions {
DEFINE_VECTORIZED_FN(time_slice_date_start_week);
DEFINE_VECTORIZED_FN(time_slice_date_start_quarter);

DEFINE_VECTORIZED_FN(time_slice_date_end_microsecond);
DEFINE_VECTORIZED_FN(time_slice_date_end_millisecond);
DEFINE_VECTORIZED_FN(time_slice_date_end_second);
DEFINE_VECTORIZED_FN(time_slice_date_end_minute);
DEFINE_VECTORIZED_FN(time_slice_date_end_hour);
Expand Down Expand Up @@ -892,4 +902,4 @@ class TimeFunctions {
friend StatusOr<ColumnPtr> do_format(const FormatCtx* ctx, const Columns& cols);
};

} // namespace starrocks
} // namespace starrocks
6 changes: 6 additions & 0 deletions be/src/types/timestamp_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,12 @@ void TimestampValue::to_timestamp(int* year, int* month, int* day, int* hour, in
timestamp::to_datetime(_timestamp, year, month, day, hour, minute, second, usec);
}

void TimestampValue::trunc_to_millisecond() {
Timestamp time = _timestamp & TIMESTAMP_BITS_TIME;
uint64_t microseconds = time % USECS_PER_MILLIS;
_timestamp -= microseconds;
}

void TimestampValue::trunc_to_second() {
Timestamp time = _timestamp & TIMESTAMP_BITS_TIME;
uint64_t microseconds = time % USECS_PER_SEC;
Expand Down
26 changes: 26 additions & 0 deletions be/src/types/timestamp_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class TimestampValue {

void to_timestamp(int* year, int* month, int* day, int* hour, int* minute, int* second, int* usec) const;

void trunc_to_millisecond();
void trunc_to_second();
void trunc_to_minute();
void trunc_to_hour();
Expand All @@ -95,6 +96,10 @@ class TimestampValue {
void trunc_to_week(int days);
void trunc_to_quarter();

template <bool end>
void floor_to_microsecond_period(long period);
template <bool end>
void floor_to_millisecond_period(long period);
template <bool end>
void floor_to_second_period(long period);
template <bool end>
Expand Down Expand Up @@ -161,6 +166,27 @@ TimestampValue TimestampValue::create(int year, int month, int day, int hour, in
return ts;
}

template <bool end>
void TimestampValue::floor_to_microsecond_period(long period) {
int64_t microseconds = ((timestamp::to_julian(_timestamp) - date::AD_EPOCH_JULIAN) * SECS_PER_DAY * USECS_PER_SEC) +
(timestamp::to_time(_timestamp));

microseconds -= microseconds % period;
if constexpr (end) {
microseconds += period;
}

JulianDate days = microseconds / (USECS_PER_SEC * SECS_PER_DAY) + date::AD_EPOCH_JULIAN;
microseconds %= (USECS_PER_SEC * SECS_PER_DAY);

_timestamp = timestamp::from_julian_and_time(days, microseconds);
}

template <bool end>
void TimestampValue::floor_to_millisecond_period(long period) {
TimestampValue::floor_to_microsecond_period<end>(period * 1000);
}

template <bool end>
void TimestampValue::floor_to_second_period(long period) {
int64_t seconds = timestamp::to_julian(_timestamp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2530,7 +2530,7 @@ interval
;

unitIdentifier
: YEAR | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND | QUARTER
: YEAR | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND | QUARTER | MILLISECOND | MICROSECOND
;

unitBoundary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ MATERIALIZED: 'MATERIALIZED';
MAX: 'MAX';
MAXVALUE: 'MAXVALUE';
MERGE: 'MERGE';
MICROSECOND: 'MICROSECOND';
MILLISECOND: 'MILLISECOND';
MIN: 'MIN';
MINUTE: 'MINUTE';
MINUS: 'MINUS';
Expand Down
89 changes: 89 additions & 0 deletions test/sql/test_function/R/test_date_trunc
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
-- name: test_date_trunc
select date_trunc('year', '2023-10-31 23:59:59.001002');
-- result:
2023-01-01 00:00:00
-- !result
select date_trunc('year', '2023-10-31');
-- result:
2023-01-01 00:00:00
-- !result
select date_trunc('quarter', '2023-10-31 23:59:59.001002');
-- result:
2023-10-01 00:00:00
-- !result
select date_trunc('quarter', '2023-10-31');
-- result:
2023-10-01 00:00:00
-- !result
select date_trunc('quarter', '2023-09-15 23:59:59.001002');
-- result:
2023-07-01 00:00:00
-- !result
select date_trunc('quarter', '2023-09-15');
-- result:
2023-07-01 00:00:00
-- !result
select date_trunc('month', '2023-10-31 23:59:59.001002');
-- result:
2023-10-01 00:00:00
-- !result
select date_trunc('month', '2023-10-31');
-- result:
2023-10-01 00:00:00
-- !result
select date_trunc('week', '2023-10-31 23:59:59.001002');
-- result:
2023-10-30 00:00:00
-- !result
select date_trunc('week', '2023-10-31');
-- result:
2023-10-30 00:00:00
-- !result
select date_trunc('day', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('day', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('hour', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 23:00:00
-- !result
select date_trunc('hour', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('minute', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 23:59:00
-- !result
select date_trunc('minute', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('second', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 23:59:59
-- !result
select date_trunc('second', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('millisecond', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 23:59:59.001000
-- !result
select date_trunc('millisecond', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
select date_trunc('microsecond', '2023-10-31 23:59:59.001002');
-- result:
2023-10-31 23:59:59.001002
-- !result
select date_trunc('microsecond', '2023-10-31');
-- result:
2023-10-31 00:00:00
-- !result
Loading

0 comments on commit 1a00830

Please sign in to comment.