This is an automated email from the ASF dual-hosted git repository.
Mryange pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new bb3890ac6c3 [Fix](ttz) Fix TIMESTAMPTZ elapsed-time semantics to use
UTC (#63161)
bb3890ac6c3 is described below
commit bb3890ac6c3cec96ba20cf8f112aed3925115334
Author: linrrarity <[email protected]>
AuthorDate: Thu May 14 16:37:15 2026 +0800
[Fix](ttz) Fix TIMESTAMPTZ elapsed-time semantics to use UTC (#63161)
Problem Summary:
Fix TIMESTAMPTZ handling for elapsed-time semantics.
TIMESTAMPTZ represents an absolute instant. For calculations that depend
on the elapsed interval between two timestamps, such as time diff
functions and time-window matching logic, Doris should use the stored
UTC time values directly. This follows PostgreSQL-style semantics and
avoids treating TIMESTAMPTZ as local DATETIME before calculation.
### Before
The previous behavior could fall back to TIMESTAMPTZ-to-DATETIME
conversion before evaluating elapsed-time logic. That conversion depends
on the session time zone and produces local wall-clock time.
This is unstable around daylight saving time transitions. During DST
fall-back or spring-forward, local wall-clock time can repeat or skip,
so two TIMESTAMPTZ values with a fixed UTC interval may produce
different or unexpected elapsed-time results after conversion to
DATETIME.
```sql
Doris> SET time_zone = '+00:00';
Doris> SELECT milliseconds_diff(
-> CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6)),
-> CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6))) AS ms_utc;
+--------+
| ms_utc |
+--------+
| 600000 |
+--------+
Doris> SET time_zone = 'America/New_York';
-- 内部计算 cast 成 datetime(local_time), 在夏令时/冬令时转换节点结果不稳定)
Doris> SELECT milliseconds_diff(
-> CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6)),
-> CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6))) AS ms_ny;
+----------+
| ms_ny |
+----------+
| -3000000 |
+----------+
```
### Now
Handle TIMESTAMPTZ directly in affected elapsed-time paths, including
scalar time interval calculations and time-window matching logic, so
they operate on UTC values instead of local DATETIME values.
Add regression coverage for DST transition cases to verify that results
are based on absolute UTC elapsed time.
```sql
Doris> SET time_zone = 'America/New_York';
Doris> SELECT milliseconds_diff(
-> CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6)),
-> CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6))) AS ms_ny;
+--------+
| ms_ny |
+--------+
| 600000 |
+--------+
```
---
be/src/core/value/timestamptz_value.h | 6 +
.../aggregate_function_sequence_match.cpp | 3 +
.../aggregate/aggregate_function_sequence_match.h | 7 +-
.../aggregate/aggregate_function_window_funnel.cpp | 7 +-
.../aggregate/aggregate_function_window_funnel.h | 34 ++--
.../aggregate_function_window_funnel_v2.cpp | 7 +-
.../aggregate_function_window_funnel_v2.h | 27 +--
.../function_date_or_datetime_computation.cpp | 6 +-
.../function_date_or_datetime_computation.h | 16 +-
.../expressions/functions/agg/SequenceCount.java | 3 +
.../functions/agg/SequenceFunction.java | 2 +-
.../expressions/functions/agg/SequenceMatch.java | 3 +
.../expressions/functions/agg/TopNWeighted.java | 8 +
.../expressions/functions/agg/WindowFunnel.java | 15 +-
.../expressions/functions/agg/WindowFunnelV2.java | 15 +-
.../expressions/functions/scalar/DateDiff.java | 3 +
.../expressions/functions/scalar/DaysDiff.java | 2 +
.../expressions/functions/scalar/HoursDiff.java | 3 +
.../functions/scalar/MicroSecondsDiff.java | 3 +
.../functions/scalar/MilliSecondsDiff.java | 3 +
.../expressions/functions/scalar/MinutesDiff.java | 3 +
.../expressions/functions/scalar/MonthsDiff.java | 7 +-
.../expressions/functions/scalar/QuartersDiff.java | 7 +-
.../expressions/functions/scalar/SecondsDiff.java | 3 +
.../expressions/functions/scalar/TimeDiff.java | 11 ++
.../expressions/functions/scalar/WeeksDiff.java | 7 +-
.../expressions/functions/scalar/YearsDiff.java | 7 +-
.../timestamptz/test_timestamptz_utc_functions.out | 33 ++++
.../test_timestamptz_utc_functions.groovy | 183 +++++++++++++++++++++
29 files changed, 378 insertions(+), 56 deletions(-)
diff --git a/be/src/core/value/timestamptz_value.h
b/be/src/core/value/timestamptz_value.h
index 1a0fa21f004..a3e3861ac2b 100644
--- a/be/src/core/value/timestamptz_value.h
+++ b/be/src/core/value/timestamptz_value.h
@@ -96,6 +96,10 @@ public:
return _utc_dt.datetime_diff_in_seconds(other._utc_dt);
}
+ int64_t datetime_diff_in_microseconds(const TimestampTzValue& other) const
{
+ return _utc_dt.datetime_diff_in_microseconds(other._utc_dt);
+ }
+
template <TimeUnit unit>
bool date_set_interval(const TimeInterval& interval) {
return _utc_dt.date_set_interval<unit>(interval);
@@ -143,6 +147,8 @@ public:
_utc_dt.unix_timestamp(timestamp, ctz);
}
+ std::string debug_string() const { return _utc_dt.debug_string(); }
+
// Convert UTC time to local time based on the given timezone
void convert_utc_to_local(const cctz::time_zone& local_time_zone,
DateV2Value<DateTimeV2ValueType>& dt) const;
diff --git a/be/src/exprs/aggregate/aggregate_function_sequence_match.cpp
b/be/src/exprs/aggregate/aggregate_function_sequence_match.cpp
index b24cf59a826..7e55c11e221 100644
--- a/be/src/exprs/aggregate/aggregate_function_sequence_match.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_sequence_match.cpp
@@ -51,6 +51,9 @@ AggregateFunctionPtr
create_aggregate_function_sequence_base(const std::string&
case TYPE_DATEV2:
return creator_without_type::create<AggregateFunction<TYPE_DATEV2>>(
argument_types, result_is_nullable, attr);
+ case TYPE_TIMESTAMPTZ:
+ return
creator_without_type::create<AggregateFunction<TYPE_TIMESTAMPTZ>>(
+ argument_types, result_is_nullable, attr);
default:
return nullptr;
}
diff --git a/be/src/exprs/aggregate/aggregate_function_sequence_match.h
b/be/src/exprs/aggregate/aggregate_function_sequence_match.h
index 292951656f5..365359da54e 100644
--- a/be/src/exprs/aggregate/aggregate_function_sequence_match.h
+++ b/be/src/exprs/aggregate/aggregate_function_sequence_match.h
@@ -73,10 +73,6 @@ constexpr auto sequence_match_max_iterations = 1000000l;
template <PrimitiveType T, typename Derived>
struct AggregateFunctionSequenceMatchData final {
using Timestamp = typename PrimitiveTypeTraits<T>::CppType;
- using NativeType =
- std::conditional_t<T == TYPE_DATEV2, uint32_t,
- std::conditional_t<T == TYPE_DATETIMEV2,
uint64_t,
- typename
PrimitiveTypeTraits<T>::CppType>>;
using Events = std::bitset<MAX_EVENTS>;
using TimestampEvents = std::pair<Timestamp, Events>;
using Comparator = ComparePairFirst<std::less>;
@@ -279,7 +275,7 @@ private:
return;
}
- NativeType duration = 0;
+ uint64_t duration = 0;
if (!parse_uint(duration)) {
throw_exception("Could not parse number");
return;
@@ -617,7 +613,6 @@ class AggregateFunctionSequenceBase
: public
IAggregateFunctionDataHelper<AggregateFunctionSequenceMatchData<T, Derived>,
Derived> {
public:
- using NativeType = typename PrimitiveTypeTraits<T>::CppType;
AggregateFunctionSequenceBase(const DataTypes& arguments)
:
IAggregateFunctionDataHelper<AggregateFunctionSequenceMatchData<T, Derived>,
Derived>(
arguments) {
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel.cpp
b/be/src/exprs/aggregate/aggregate_function_window_funnel.cpp
index d2de78777ba..3c1a35e1e06 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel.cpp
@@ -37,10 +37,13 @@ AggregateFunctionPtr
create_aggregate_function_window_funnel(const std::string&
return nullptr;
}
if (argument_types[2]->get_primitive_type() == TYPE_DATETIMEV2) {
- return creator_without_type::create<AggregateFunctionWindowFunnel>(
+ return
creator_without_type::create<AggregateFunctionWindowFunnel<TYPE_DATETIMEV2>>(
+ argument_types, result_is_nullable, attr);
+ } else if (argument_types[2]->get_primitive_type() == TYPE_TIMESTAMPTZ) {
+ return
creator_without_type::create<AggregateFunctionWindowFunnel<TYPE_TIMESTAMPTZ>>(
argument_types, result_is_nullable, attr);
} else {
- LOG(WARNING) << "Only support DateTime type as window argument!";
+ LOG(WARNING) << "Only support DateTime or TimeStampTz type as window
argument!";
return nullptr;
}
}
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel.h
b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
index 859a91c8451..618358f276d 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel.h
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
@@ -69,9 +69,11 @@ inline WindowFunnelMode string_to_window_funnel_mode(const
String& string) {
}
}
+template <PrimitiveType T>
struct DataValue {
using TimestampEvent = std::vector<ColumnUInt8::Container>;
- std::vector<DateV2Value<DateTimeV2ValueType>> dt;
+ using DateValueType = typename PrimitiveTypeTraits<T>::CppType;
+ std::vector<DateValueType> dt;
TimestampEvent event_columns_data;
bool operator<(const DataValue& other) const { return dt < other.dt; }
void clear() {
@@ -96,15 +98,16 @@ struct DataValue {
}
};
+template <PrimitiveType T>
struct WindowFunnelState {
- static constexpr PrimitiveType PType = PrimitiveType::TYPE_DATETIMEV2;
- using NativeType = UInt64;
- using DateValueType = DateV2Value<DateTimeV2ValueType>;
+ static constexpr PrimitiveType PType = T;
+ using NativeType = typename PrimitiveTypeTraits<T>::StorageFieldType;
+ using DateValueType = typename PrimitiveTypeTraits<T>::CppType;
int event_count = 0;
int64_t window;
bool enable_mode;
WindowFunnelMode window_funnel_mode;
- DataValue events_list;
+ DataValue<T> events_list;
WindowFunnelState() {
event_count = 0;
@@ -122,7 +125,8 @@ struct WindowFunnelState {
window = win;
window_funnel_mode = enable_mode ? mode : WindowFunnelMode::DEFAULT;
events_list.dt.emplace_back(
- assert_cast<const
ColumnVector<PType>&>(*arg_columns[2]).get_data()[row_num]);
+ assert_cast<const typename
PrimitiveTypeTraits<PType>::ColumnType&>(*arg_columns[2])
+ .get_data()[row_num]);
for (int i = 0; i < event_count; i++) {
events_list.event_columns_data[i].emplace_back(
assert_cast<const ColumnUInt8&>(*arg_columns[3 +
i]).get_data()[row_num]);
@@ -267,7 +271,7 @@ struct WindowFunnelState {
}
}
- void merge(const WindowFunnelState& other) {
+ void merge(const WindowFunnelState<T>& other) {
if (other.events_list.empty()) {
return;
}
@@ -326,7 +330,9 @@ struct WindowFunnelState {
events_list.clear();
events_list.dt.resize(size);
for (auto i = 0; i < size; i++) {
- read_var_int(*reinterpret_cast<Int64*>(&events_list.dt[i]), in);
+ Int64 timestamp = 0;
+ read_var_int(timestamp, in);
+ events_list.dt[i] = DateValueType(static_cast<UInt64>(timestamp));
}
events_list.event_columns_data.resize(event_count);
for (int64_t i = 0; i < event_count; i++) {
@@ -341,17 +347,19 @@ struct WindowFunnelState {
}
};
+template <PrimitiveType T>
class AggregateFunctionWindowFunnel final
- : public IAggregateFunctionDataHelper<WindowFunnelState,
AggregateFunctionWindowFunnel>,
+ : public IAggregateFunctionDataHelper<WindowFunnelState<T>,
+
AggregateFunctionWindowFunnel<T>>,
MultiExpression,
NullableAggregateFunction {
public:
AggregateFunctionWindowFunnel(const DataTypes& argument_types_)
- : IAggregateFunctionDataHelper<WindowFunnelState,
AggregateFunctionWindowFunnel>(
+ : IAggregateFunctionDataHelper<WindowFunnelState<T>,
AggregateFunctionWindowFunnel<T>>(
argument_types_) {}
void create(AggregateDataPtr __restrict place) const override {
- auto data = new (place) WindowFunnelState(
+ auto data = new (place) WindowFunnelState<T>(
cast_set<int>(IAggregateFunction::get_argument_types().size()
- 3));
/// support window funnel mode from 2.0. See
`BeExecVersionManager::max_be_exec_version`
data->enable_mode = IAggregateFunction::version >= 3;
@@ -389,8 +397,8 @@ public:
// place is essentially an AggregateDataPtr, passed as a
ConstAggregateDataPtr.
this->data(const_cast<AggregateDataPtr>(place)).sort();
assert_cast<ColumnInt32&>(to).get_data().push_back(
- IAggregateFunctionDataHelper<WindowFunnelState,
-
AggregateFunctionWindowFunnel>::data(place)
+ IAggregateFunctionDataHelper<WindowFunnelState<T>,
+
AggregateFunctionWindowFunnel<T>>::data(place)
.get());
}
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.cpp
b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.cpp
index a1028416d14..e54ec1f92b7 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.cpp
@@ -39,10 +39,13 @@ AggregateFunctionPtr
create_aggregate_function_window_funnel_v2(const std::strin
return nullptr;
}
if (argument_types[2]->get_primitive_type() == TYPE_DATETIMEV2) {
- return creator_without_type::create<AggregateFunctionWindowFunnelV2>(
+ return
creator_without_type::create<AggregateFunctionWindowFunnelV2<TYPE_DATETIMEV2>>(
+ argument_types, result_is_nullable, attr);
+ } else if (argument_types[2]->get_primitive_type() == TYPE_TIMESTAMPTZ) {
+ return
creator_without_type::create<AggregateFunctionWindowFunnelV2<TYPE_TIMESTAMPTZ>>(
argument_types, result_is_nullable, attr);
} else {
- LOG(WARNING) << "Only support DateTime type as window argument!";
+ LOG(WARNING) << "Only support DateTime or TimeStampTz type as window
argument!";
return nullptr;
}
}
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
index fb0a72363b0..e5a0bcaec6e 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
@@ -76,6 +76,7 @@ void merge_events_list(T& events_list, size_t prefix_size,
bool prefix_sorted, b
/// The algorithm uses this to ensure each funnel step comes from a different
row.
///
/// This approach adds ZERO storage overhead — each event remains 9 bytes
(UInt64 + UInt8).
+template <PrimitiveType T>
struct WindowFunnelStateV2 {
/// (timestamp_int_val, 1-based event_index with continuation flag in bit
7)
///
@@ -135,10 +136,10 @@ struct WindowFunnelStateV2 {
window = win;
window_funnel_mode = mode;
- // get_data() returns DateV2Value<DateTimeV2ValueType>; convert to
packed UInt64
- auto timestamp = assert_cast<const
ColumnVector<TYPE_DATETIMEV2>&>(*arg_columns[2])
- .get_data()[row_num]
- .to_date_int_val();
+ auto timestamp =
+ assert_cast<const typename
PrimitiveTypeTraits<T>::ColumnType&>(*arg_columns[2])
+ .get_data()[row_num]
+ .to_date_int_val();
// Iterate from last event to first (reverse order).
// This ensures that after stable_sort, events with the same timestamp
@@ -173,7 +174,7 @@ struct WindowFunnelStateV2 {
}
}
- void merge(const WindowFunnelStateV2& other) {
+ void merge(const WindowFunnelStateV2<T>& other) {
if (other.events_list.empty()) {
return;
}
@@ -616,20 +617,22 @@ private:
}
};
+template <PrimitiveType T>
class AggregateFunctionWindowFunnelV2 final
- : public IAggregateFunctionDataHelper<WindowFunnelStateV2,
AggregateFunctionWindowFunnelV2>,
+ : public IAggregateFunctionDataHelper<WindowFunnelStateV2<T>,
+
AggregateFunctionWindowFunnelV2<T>>,
MultiExpression,
NullableAggregateFunction {
public:
AggregateFunctionWindowFunnelV2(const DataTypes& argument_types_)
- : IAggregateFunctionDataHelper<WindowFunnelStateV2,
AggregateFunctionWindowFunnelV2>(
- argument_types_) {
- WindowFunnelStateV2::validate_event_count(
+ : IAggregateFunctionDataHelper<WindowFunnelStateV2<T>,
+
AggregateFunctionWindowFunnelV2<T>>(argument_types_) {
+ WindowFunnelStateV2<T>::validate_event_count(
cast_set<int>(IAggregateFunction::get_argument_types().size()
- 3));
}
void create(AggregateDataPtr __restrict place) const override {
- new (place) WindowFunnelStateV2(
+ new (place) WindowFunnelStateV2<T>(
cast_set<int>(IAggregateFunction::get_argument_types().size()
- 3));
}
@@ -664,8 +667,8 @@ public:
void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn&
to) const override {
this->data(const_cast<AggregateDataPtr>(place)).sort();
assert_cast<ColumnInt32&>(to).get_data().push_back(
- IAggregateFunctionDataHelper<WindowFunnelStateV2,
-
AggregateFunctionWindowFunnelV2>::data(place)
+ IAggregateFunctionDataHelper<WindowFunnelStateV2<T>,
+
AggregateFunctionWindowFunnelV2<T>>::data(place)
.get());
}
diff --git a/be/src/exprs/function/function_date_or_datetime_computation.cpp
b/be/src/exprs/function/function_date_or_datetime_computation.cpp
index 26cda7e4138..8973cab77e3 100644
--- a/be/src/exprs/function/function_date_or_datetime_computation.cpp
+++ b/be/src/exprs/function/function_date_or_datetime_computation.cpp
@@ -186,7 +186,8 @@ using FunctionSubTimeTimestampTz =
#define ALL_FUNCTION_TIME_DIFF(NAME, IMPL) \
FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATETIMEV2) \
- FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATEV2)
+ FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_DATEV2) \
+ FUNCTION_TIME_DIFF(NAME, IMPL, TYPE_TIMESTAMPTZ)
// these diff functions accept all v2 types. but for v1 only datetime.
ALL_FUNCTION_TIME_DIFF(FunctionDatetimeDateDiff, DateDiffImpl)
ALL_FUNCTION_TIME_DIFF(FunctionDatetimeTimeDiff, TimeDiffImpl)
@@ -324,7 +325,8 @@ void
register_function_date_time_computation(SimpleFunctionFactory& factory) {
#define REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(NAME) \
REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATETIMEV2) \
- REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATEV2)
+ REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_DATEV2) \
+ REGISTER_DATEV2_FUNCTIONS_DIFF(NAME, TYPE_TIMESTAMPTZ)
REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(FunctionDatetimeDateDiff)
REGISTER_ALL_DATEV2_FUNCTIONS_DIFF(FunctionDatetimeTimeDiff)
diff --git a/be/src/exprs/function/function_date_or_datetime_computation.h
b/be/src/exprs/function/function_date_or_datetime_computation.h
index 9aa3332e937..939eade4ea4 100644
--- a/be/src/exprs/function/function_date_or_datetime_computation.h
+++ b/be/src/exprs/function/function_date_or_datetime_computation.h
@@ -573,7 +573,8 @@ struct TimeDiffImpl {
using ValueType = typename PrimitiveTypeTraits<DateType>::CppType;
using ArgType = typename
PrimitiveTypeTraits<DateType>::DataType::FieldType;
//TODO: remove V1 since FE already removed it.
- static constexpr bool UsingTimev2 = is_date_v2_or_datetime_v2(DateType);
+ static constexpr bool UsingTimev2 =
+ is_date_v2_or_datetime_v2(DateType) || DateType ==
TYPE_TIMESTAMPTZ;
static constexpr PrimitiveType ReturnType = TYPE_TIMEV2;
static constexpr auto name = "timediff";
@@ -601,8 +602,19 @@ struct TimeDiffImpl {
return
std::make_shared<DataTypeTimeV2>(arguments[0].type->get_scale());
}
};
+
+template <TimeUnit UNIT, typename T0, typename T1>
+int64_t diff_on_utc_datetime(const T0& ts1, const T1& ts0) {
+ return datetime_diff<UNIT>(ts1, ts0);
+}
+
+template <TimeUnit UNIT>
+int64_t diff_on_utc_datetime(const TimestampTzValue& ts1, const
TimestampTzValue& ts0) {
+ return datetime_diff<UNIT>(ts1.utc_dt(), ts0.utc_dt());
+}
+
#define TIME_DIFF_FUNCTION_IMPL(CLASS, NAME, UNIT) \
- DECLARE_DATE_FUNCTIONS(CLASS, NAME, TYPE_BIGINT,
datetime_diff<TimeUnit::UNIT>(ts1, ts0))
+ DECLARE_DATE_FUNCTIONS(CLASS, NAME, TYPE_BIGINT,
diff_on_utc_datetime<TimeUnit::UNIT>(ts1, ts0))
// all these functions implemented by datediff
TIME_DIFF_FUNCTION_IMPL(YearsDiffImpl, years_diff, YEAR);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
index 5cbc0903979..e4ad5956c1c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceCount.java
@@ -27,6 +27,7 @@ import org.apache.doris.nereids.types.BooleanType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.base.Preconditions;
@@ -43,6 +44,8 @@ public class SequenceCount extends
NotNullableAggregateFunction
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(BigIntType.INSTANCE)
.varArgs(StringType.INSTANCE, DateV2Type.INSTANCE,
BooleanType.INSTANCE),
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .varArgs(StringType.INSTANCE, TimeStampTzType.WILDCARD,
BooleanType.INSTANCE),
FunctionSignature.ret(BigIntType.INSTANCE)
.varArgs(StringType.INSTANCE, DateTimeV2Type.WILDCARD,
BooleanType.INSTANCE)
);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
index 673c91479a4..6bbf4e6e992 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceFunction.java
@@ -36,7 +36,7 @@ public interface SequenceFunction extends FunctionTrait {
}
if (!getArgumentType(1).isDateLikeType()) {
throw new AnalysisException("The timestamp params of " +
functionName
- + " function must be DATE or DATETIME, but it is " +
getArgumentType(1));
+ + " function must be DATE, DATETIME or TIMESTAMPTZ, but it
is " + getArgumentType(1));
}
String pattern = ((StringLikeLiteral) firstArg).getStringValue();
if (!FunctionCallExpr.parsePattern(pattern)) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
index c6cf9e436a4..c9f15731a19 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/SequenceMatch.java
@@ -25,6 +25,7 @@ import org.apache.doris.nereids.types.BooleanType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.base.Preconditions;
@@ -41,6 +42,8 @@ public class SequenceMatch extends NullableAggregateFunction
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
FunctionSignature.ret(BooleanType.INSTANCE)
.varArgs(StringType.INSTANCE, DateV2Type.INSTANCE,
BooleanType.INSTANCE),
+ FunctionSignature.ret(BooleanType.INSTANCE)
+ .varArgs(StringType.INSTANCE, TimeStampTzType.WILDCARD,
BooleanType.INSTANCE),
FunctionSignature.ret(BooleanType.INSTANCE)
.varArgs(StringType.INSTANCE, DateTimeV2Type.WILDCARD,
BooleanType.INSTANCE)
);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
index 79db1318c62..1ed1586f99f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/TopNWeighted.java
@@ -35,6 +35,7 @@ import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.LargeIntType;
import org.apache.doris.nereids.types.SmallIntType;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.types.TinyIntType;
import org.apache.doris.nereids.types.VarcharType;
@@ -71,6 +72,8 @@ public class TopNWeighted extends NullableAggregateFunction
.args(FloatType.INSTANCE,
BigIntType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(ArrayType.of(DateV2Type.INSTANCE))
.args(DateV2Type.INSTANCE, BigIntType.INSTANCE,
IntegerType.INSTANCE),
+ FunctionSignature.ret(ArrayType.of(TimeStampTzType.WILDCARD))
+ .args(TimeStampTzType.WILDCARD, BigIntType.INSTANCE,
IntegerType.INSTANCE),
FunctionSignature.ret(ArrayType.of(DateTimeV2Type.WILDCARD))
.args(DateTimeV2Type.WILDCARD, BigIntType.INSTANCE,
IntegerType.INSTANCE),
FunctionSignature.ret(ArrayType.of(StringType.INSTANCE))
@@ -105,6 +108,11 @@ public class TopNWeighted extends NullableAggregateFunction
IntegerType.INSTANCE),
FunctionSignature.ret(ArrayType.of(DateV2Type.INSTANCE))
.args(DateV2Type.INSTANCE, BigIntType.INSTANCE,
IntegerType.INSTANCE, IntegerType.INSTANCE),
+ FunctionSignature.ret(ArrayType.of(TimeStampTzType.WILDCARD))
+ .args(TimeStampTzType.WILDCARD,
+ BigIntType.INSTANCE,
+ IntegerType.INSTANCE,
+ IntegerType.INSTANCE),
FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT)
.args(DateTimeV2Type.WILDCARD,
BigIntType.INSTANCE,
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
index 848d3cfd6d5..ef60c0a8c07 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnel.java
@@ -24,14 +24,17 @@ import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSi
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.util.List;
@@ -42,6 +45,9 @@ public class WindowFunnel extends NullableAggregateFunction
implements ExplicitlyCastableSignature {
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(IntegerType.INSTANCE)
+ .varArgs(BigIntType.INSTANCE, StringType.INSTANCE,
TimeStampTzType.WILDCARD,
+ BooleanType.INSTANCE),
FunctionSignature.ret(IntegerType.INSTANCE)
.varArgs(BigIntType.INSTANCE, StringType.INSTANCE,
DateTimeV2Type.WILDCARD,
BooleanType.INSTANCE)
@@ -84,7 +90,8 @@ public class WindowFunnel extends NullableAggregateFunction
throw new AnalysisException("The mode params of " + functionName +
" function must be string");
}
if (!getArgumentType(2).isDateLikeType()) {
- throw new AnalysisException("The 3rd param of " + functionName + "
function must be DATE or DATETIME");
+ throw new AnalysisException("The 3rd param of " + functionName
+ + " function must be DATE, DATETIME or TIMESTAMPTZ");
}
for (int i = 3; i < arity(); i++) {
if (!getArgumentType(i).isBooleanType()) {
@@ -98,9 +105,9 @@ public class WindowFunnel extends NullableAggregateFunction
public FunctionSignature computeSignature(FunctionSignature signature) {
FunctionSignature functionSignature =
super.computeSignature(signature);
if (functionSignature.getArgType(2) instanceof DateV2Type) {
- return functionSignature.withArgumentTypes(getArguments(), (index,
originType, arg) ->
- (index == 2) ? DateTimeV2Type.SYSTEM_DEFAULT : originType
- );
+ List<DataType> newTypes =
Lists.newArrayList(functionSignature.argumentsTypes);
+ newTypes.set(2, DateTimeV2Type.SYSTEM_DEFAULT);
+ return
functionSignature.withArgumentTypes(functionSignature.hasVarArgs, newTypes);
}
return functionSignature;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnelV2.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnelV2.java
index fa4f5d8e469..697774eb47f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnelV2.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/WindowFunnelV2.java
@@ -24,14 +24,17 @@ import
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSi
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.util.ExpressionUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import java.util.List;
@@ -45,6 +48,9 @@ public class WindowFunnelV2 extends NullableAggregateFunction
public static final int MAX_EVENT_CONDITIONS = 127;
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(IntegerType.INSTANCE)
+ .varArgs(BigIntType.INSTANCE, StringType.INSTANCE,
TimeStampTzType.WILDCARD,
+ BooleanType.INSTANCE),
FunctionSignature.ret(IntegerType.INSTANCE)
.varArgs(BigIntType.INSTANCE, StringType.INSTANCE,
DateTimeV2Type.WILDCARD,
BooleanType.INSTANCE)
@@ -93,7 +99,8 @@ public class WindowFunnelV2 extends NullableAggregateFunction
throw new AnalysisException("The mode params of " + functionName +
" function must be string");
}
if (!getArgumentType(2).isDateLikeType()) {
- throw new AnalysisException("The 3rd param of " + functionName + "
function must be DATE or DATETIME");
+ throw new AnalysisException("The 3rd param of " + functionName
+ + " function must be DATE, DATETIME or TIMESTAMPTZ");
}
for (int i = 3; i < arity(); i++) {
if (!getArgumentType(i).isBooleanType()) {
@@ -107,9 +114,9 @@ public class WindowFunnelV2 extends
NullableAggregateFunction
public FunctionSignature computeSignature(FunctionSignature signature) {
FunctionSignature functionSignature =
super.computeSignature(signature);
if (functionSignature.getArgType(2) instanceof DateV2Type) {
- return functionSignature.withArgumentTypes(getArguments(), (index,
originType, arg) ->
- (index == 2) ? DateTimeV2Type.SYSTEM_DEFAULT : originType
- );
+ List<DataType> newTypes =
Lists.newArrayList(functionSignature.argumentsTypes);
+ newTypes.set(2, DateTimeV2Type.SYSTEM_DEFAULT);
+ return
functionSignature.withArgumentTypes(functionSignature.hasVarArgs, newTypes);
}
return functionSignature;
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
index 16a2e1cf325..2d766295f64 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateDiff.java
@@ -26,6 +26,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.IntegerType;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -39,6 +40,8 @@ public class DateDiff extends ScalarFunction
implements BinaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(IntegerType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(IntegerType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
FunctionSignature.ret(IntegerType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
index f894c9f09a6..012ad7c6399 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DaysDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,6 +42,7 @@ public class DaysDiff extends ScalarFunction implements
BinaryExpression, Explic
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+
FunctionSignature.ret(BigIntType.INSTANCE).args(TimeStampTzType.WILDCARD,
TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE).args(DateTimeV2Type.WILDCARD,
DateTimeV2Type.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
index b4d8f4ce181..c601497c45d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/HoursDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class HoursDiff extends ScalarFunction implements
BinaryExpression, Expli
PropagateNullable, DateDiffMonotonic {
public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
index 434043119a0..26081a347a0 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MicroSecondsDiff.java
@@ -27,6 +27,7 @@ import
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -40,6 +41,8 @@ public class MicroSecondsDiff extends ScalarFunction
implements BinaryExpression
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
index 3f07927f920..9cda6cb8e4a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MilliSecondsDiff.java
@@ -27,6 +27,7 @@ import
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -40,6 +41,8 @@ public class MilliSecondsDiff extends ScalarFunction
implements BinaryExpression
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
index a66b5beb53f..f1a320932f0 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MinutesDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class MinutesDiff extends ScalarFunction implements
BinaryExpression, Exp
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
index 32735b3931e..7c11156861b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/MonthsDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class MonthsDiff extends ScalarFunction implements
BinaryExpression, Expl
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE),
FunctionSignature.ret(BigIntType.INSTANCE)
- .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
/**
* constructor with 2 arguments.
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
index d13b49db683..ec8f889baa5 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/QuartersDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class QuartersDiff extends ScalarFunction implements
BinaryExpression, Ex
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE),
FunctionSignature.ret(BigIntType.INSTANCE)
- .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE)
);
/**
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
index aab4fb18054..bb7df199d28 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/SecondsDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,6 +42,8 @@ public class SecondsDiff extends ScalarFunction implements
BinaryExpression, Exp
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
index 7602743ec5c..a25ce2d45f8 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/TimeDiff.java
@@ -25,6 +25,7 @@ import
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import org.apache.doris.nereids.types.TimeV2Type;
import com.google.common.base.Preconditions;
@@ -39,6 +40,8 @@ public class TimeDiff extends ScalarFunction
implements BinaryExpression, ExplicitlyCastableSignature,
PropagateNullable {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
+ FunctionSignature.ret(TimeV2Type.WILDCARD)
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
FunctionSignature.ret(TimeV2Type.WILDCARD)
.args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
FunctionSignature.ret(TimeV2Type.SYSTEM_DEFAULT).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
@@ -83,11 +86,19 @@ public class TimeDiff extends ScalarFunction
DateTimeV2Type left = (DateTimeV2Type)
getArgument(0).getDataType();
scale = Math.max(scale, left.getScale());
useTimev2 = true;
+ } else if (getArgument(0).getDataType() instanceof TimeStampTzType) {
+ TimeStampTzType left = (TimeStampTzType)
getArgument(0).getDataType();
+ scale = Math.max(scale, left.getScale());
+ useTimev2 = true;
}
if (getArgument(1).getDataType() instanceof DateTimeV2Type) {
DateTimeV2Type right = (DateTimeV2Type)
getArgument(1).getDataType();
scale = Math.max(scale, right.getScale());
useTimev2 = true;
+ } else if (getArgument(1).getDataType() instanceof TimeStampTzType) {
+ TimeStampTzType right = (TimeStampTzType)
getArgument(1).getDataType();
+ scale = Math.max(scale, right.getScale());
+ useTimev2 = true;
}
if (useTimev2) {
signature = signature.withReturnType(TimeV2Type.of(scale));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
index cc884d44911..771d43d2cb3 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/WeeksDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class WeeksDiff extends ScalarFunction implements
BinaryExpression, Expli
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE),
FunctionSignature.ret(BigIntType.INSTANCE)
- .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
/**
* constructor with 2 arguments.
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
index 060daf4fc57..da227338e0a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/YearsDiff.java
@@ -28,6 +28,7 @@ import
org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.BigIntType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateV2Type;
+import org.apache.doris.nereids.types.TimeStampTzType;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -41,9 +42,11 @@ public class YearsDiff extends ScalarFunction implements
BinaryExpression, Expli
PropagateNullable, DateDiffMonotonic {
private static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE),
FunctionSignature.ret(BigIntType.INSTANCE)
- .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD));
+ .args(TimeStampTzType.WILDCARD, TimeStampTzType.WILDCARD),
+ FunctionSignature.ret(BigIntType.INSTANCE)
+ .args(DateTimeV2Type.WILDCARD, DateTimeV2Type.WILDCARD),
+
FunctionSignature.ret(BigIntType.INSTANCE).args(DateV2Type.INSTANCE,
DateV2Type.INSTANCE));
/**
* constructor with 2 arguments.
diff --git
a/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
b/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
new file mode 100644
index 00000000000..12744160ea0
--- /dev/null
+++
b/regression-test/data/datatype_p0/timestamptz/test_timestamptz_utc_functions.out
@@ -0,0 +1,33 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !timestamptz_diff_utc --
+600000 600000000 600 10 0 0 0 0 0
0 0 00:10:00.000000
+
+-- !timestamptz_diff_ny --
+600000 600000000 600 10 0 0 0 0 0
0 0 00:10:00.000000
+
+-- !timestamptz_diff_spring_forward_ny --
+600000 600 10 0 00:10:00.000000
+
+-- !timestamptz_diff_mixed_scale_ny --
+600123 600123000 600 00:10:00.123
+
+-- !timestamptz_agg_utc --
+true 1 2 2
+
+-- !timestamptz_agg_ny --
+true 1 2 2
+
+-- !timestamptz_agg_by_group_ny --
+1 true 1 2 2
+3 true 1 2 2
+
+-- !timestamptz_column_diff_ny --
+600000 600 00:10:00.000000
+
+-- !timestamptz_topn_weighted --
+1 2024-11-03 06:30:00.000000+00:00 2024-11-03 06:30:00.000000+00:00
+3 2024-03-10 07:30:00.000000+00:00 2024-03-10 07:30:00.000000+00:00
+
+-- !timestamptz_null --
+\N 0
+
diff --git
a/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
new file mode 100644
index 00000000000..69c15e4d197
--- /dev/null
+++
b/regression-test/suites/datatype_p0/timestamptz/test_timestamptz_utc_functions.groovy
@@ -0,0 +1,183 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_timestamptz_utc_functions") {
+ sql "SET enable_nereids_planner = true;"
+ sql "SET enable_fallback_to_original_planner = false;"
+
+ // Fall-back DST fold:
+ // lhs UTC=2024-11-03 06:05:00, NY local=2024-11-03 01:05:00;
+ // rhs UTC=2024-11-03 05:55:00, NY local=2024-11-03 01:55:00.
+ // Expected: TIMESTAMPTZ functions use UTC instants, so lhs - rhs = +10
minutes, not local -50 minutes.
+ def lhs = "CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6))"
+ def rhs = "CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6))"
+
+ // Spring-forward DST gap:
+ // lhs UTC=2024-03-10 07:05:00, NY local=2024-03-10 03:05:00;
+ // rhs UTC=2024-03-10 06:55:00, NY local=2024-03-10 01:55:00.
+ // Expected: TIMESTAMPTZ functions use UTC instants, so lhs - rhs = +10
minutes, not local +70 minutes.
+ def springLhs = "CAST('2024-03-10 03:05:00 -04:00' AS TIMESTAMPTZ(6))"
+ def springRhs = "CAST('2024-03-10 01:55:00 -05:00' AS TIMESTAMPTZ(6))"
+
+ // Mixed scale: lhs UTC=2024-11-03 06:05:00.123, rhs UTC=2024-11-03
05:55:00.
+ // Expected: lhs - rhs = +600123 ms, and non-default TIMESTAMPTZ scales
bind directly.
+ def scale3Lhs = "CAST('2024-11-03 01:05:00.123 -05:00' AS TIMESTAMPTZ(3))"
+ def scale0Rhs = "CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(0))"
+
+ // Scalar diff results should be identical in UTC and America/New_York
sessions.
+ sql "SET time_zone = '+00:00';"
+ qt_timestamptz_diff_utc """
+ SELECT milliseconds_diff(${lhs}, ${rhs}) AS ms_diff,
+ microseconds_diff(${lhs}, ${rhs}) AS us_diff,
+ seconds_diff(${lhs}, ${rhs}) AS sec_diff,
+ minutes_diff(${lhs}, ${rhs}) AS min_diff,
+ hours_diff(${lhs}, ${rhs}) AS hour_diff,
+ days_diff(${lhs}, ${rhs}) AS day_diff,
+ weeks_diff(${lhs}, ${rhs}) AS week_diff,
+ months_diff(${lhs}, ${rhs}) AS month_diff,
+ quarters_diff(${lhs}, ${rhs}) AS quarter_diff,
+ years_diff(${lhs}, ${rhs}) AS year_diff,
+ datediff(${lhs}, ${rhs}) AS date_diff,
+ timediff(${lhs}, ${rhs}) AS time_diff;
+ """
+
+ sql "SET time_zone = 'America/New_York';"
+ qt_timestamptz_diff_ny """
+ SELECT milliseconds_diff(${lhs}, ${rhs}) AS ms_diff,
+ microseconds_diff(${lhs}, ${rhs}) AS us_diff,
+ seconds_diff(${lhs}, ${rhs}) AS sec_diff,
+ minutes_diff(${lhs}, ${rhs}) AS min_diff,
+ hours_diff(${lhs}, ${rhs}) AS hour_diff,
+ days_diff(${lhs}, ${rhs}) AS day_diff,
+ weeks_diff(${lhs}, ${rhs}) AS week_diff,
+ months_diff(${lhs}, ${rhs}) AS month_diff,
+ quarters_diff(${lhs}, ${rhs}) AS quarter_diff,
+ years_diff(${lhs}, ${rhs}) AS year_diff,
+ datediff(${lhs}, ${rhs}) AS date_diff,
+ timediff(${lhs}, ${rhs}) AS time_diff;
+ """
+
+ qt_timestamptz_diff_spring_forward_ny """
+ SELECT milliseconds_diff(${springLhs}, ${springRhs}) AS ms_diff,
+ seconds_diff(${springLhs}, ${springRhs}) AS sec_diff,
+ minutes_diff(${springLhs}, ${springRhs}) AS min_diff,
+ hours_diff(${springLhs}, ${springRhs}) AS hour_diff,
+ timediff(${springLhs}, ${springRhs}) AS time_diff;
+ """
+
+ qt_timestamptz_diff_mixed_scale_ny """
+ SELECT milliseconds_diff(${scale3Lhs}, ${scale0Rhs}) AS ms_diff,
+ microseconds_diff(${scale3Lhs}, ${scale0Rhs}) AS us_diff,
+ seconds_diff(${scale3Lhs}, ${scale0Rhs}) AS sec_diff,
+ timediff(${scale3Lhs}, ${scale0Rhs}) AS time_diff;
+ """
+
+ testFoldConst("""
+ SELECT milliseconds_diff(${lhs}, ${rhs}),
+ seconds_diff(${lhs}, ${rhs}),
+ timediff(${lhs}, ${rhs});
+ """)
+
+ sql "DROP TABLE IF EXISTS tz_utc_function_events;"
+ sql """
+ CREATE TABLE tz_utc_function_events (
+ id INT,
+ grp INT,
+ weight BIGINT,
+ ts TIMESTAMPTZ(6),
+ e1 BOOLEAN,
+ e2 BOOLEAN
+ )
+ DUPLICATE KEY(id)
+ DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES('replication_num' = '1');
+ """
+ sql """
+ INSERT INTO tz_utc_function_events VALUES
+ (1, 1, 10, CAST('2024-11-03 01:55:00 -04:00' AS TIMESTAMPTZ(6)), true,
false),
+ (2, 1, 20, CAST('2024-11-03 01:05:00 -05:00' AS TIMESTAMPTZ(6)),
false, true),
+ (3, 1, 30, CAST('2024-11-03 01:30:00 -05:00' AS TIMESTAMPTZ(6)),
false, false),
+ (4, 2, 40, NULL, true, false),
+ (5, 3, 50, CAST('2024-03-10 01:55:00 -05:00' AS TIMESTAMPTZ(6)), true,
false),
+ (6, 3, 60, CAST('2024-03-10 03:05:00 -04:00' AS TIMESTAMPTZ(6)),
false, true),
+ (7, 3, 70, CAST('2024-03-10 03:30:00 -04:00' AS TIMESTAMPTZ(6)),
false, false);
+ """
+
+ // Aggregates should also compare TIMESTAMPTZ values by UTC instant.
+ sql "SET time_zone = '+00:00';"
+ qt_timestamptz_agg_utc """
+ SELECT sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+ sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+ window_funnel(600, 'default', ts, e1, e2) AS funnel_v1,
+ window_funnel_v2(600, 'default', ts, e1, e2) AS funnel_v2
+ FROM tz_utc_function_events
+ WHERE grp = 1;
+ """
+
+ sql "SET time_zone = 'America/New_York';"
+ qt_timestamptz_agg_ny """
+ SELECT sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+ sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+ window_funnel(600, 'default', ts, e1, e2) AS funnel_v1,
+ window_funnel_v2(600, 'default', ts, e1, e2) AS funnel_v2
+ FROM tz_utc_function_events
+ WHERE grp = 1;
+ """
+
+ // Grouped aggregation verifies both DST shapes.
+ order_qt_timestamptz_agg_by_group_ny """
+ SELECT grp,
+ sequence_match('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_match,
+ sequence_count('(?1)(?t<=600)(?2)', ts, e1, e2) AS seq_count,
+ window_funnel(600, 'default', ts, e1, e2) AS funnel_v1,
+ window_funnel_v2(600, 'default', ts, e1, e2) AS funnel_v2
+ FROM tz_utc_function_events
+ WHERE grp IN (1, 3)
+ GROUP BY grp
+ ORDER BY grp;
+ """
+
+ // Column inputs should also use UTC instant semantics.
+ qt_timestamptz_column_diff_ny """
+ SELECT milliseconds_diff(t2.ts, t1.ts) AS ms_diff,
+ seconds_diff(t2.ts, t1.ts) AS sec_diff,
+ timediff(t2.ts, t1.ts) AS time_diff
+ FROM tz_utc_function_events t1, tz_utc_function_events t2
+ WHERE t1.id = 1 AND t2.id = 2;
+ """
+
+ // topn_weighted should preserve TIMESTAMPTZ as the result array item type.
+ sql "SET time_zone = '+00:00';"
+ order_qt_timestamptz_topn_weighted """
+ SELECT grp,
+ CAST(topn_weighted(ts, weight, 2)[1] AS VARCHAR(64)) AS top_ts,
+ CAST(topn_weighted(ts, weight, 2, 100)[1] AS VARCHAR(64)) AS
top_ts_with_default
+ FROM tz_utc_function_events
+ WHERE grp IN (1, 3)
+ GROUP BY grp
+ ORDER BY grp;
+ """
+
+ // NULL input remains NULL, and sequence_count ignores the NULL timestamp
row.
+ qt_timestamptz_null """
+ SELECT milliseconds_diff(MAX(ts), NULL), sequence_count('(?1)(?2)',
ts, e1, e2)
+ FROM tz_utc_function_events
+ WHERE grp = 2;
+ """
+
+ sql "SET time_zone = default;"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]