2424
2525#include " pipeline/common/join_utils.h"
2626#include " vec/columns/column_vector.h"
27+ #include " vec/runtime/timestamptz_value.h"
2728
2829namespace doris {
2930using namespace vectorized ;
@@ -113,6 +114,22 @@ TEST_F(AsofIndexGroupFinalizeTest, SortAndFinalizeRetainsValueRowAlignment) {
113114 }
114115}
115116
117+ TEST_F (AsofIndexGroupFinalizeTest, SingleElementSkipsPdqsort) {
118+ auto group = make_group<uint32_t >({{42 , 7 }});
119+ EXPECT_TRUE (group.entries .empty ());
120+ ASSERT_EQ (group.asof_values .size (), 1U );
121+ EXPECT_EQ (group.asof_values [0 ], 42U );
122+ EXPECT_EQ (group.row_indexes [0 ], 7U );
123+ }
124+
125+ TEST_F (AsofIndexGroupFinalizeTest, DoubleFinalizeIsIdempotent) {
126+ auto group = make_group<uint32_t >({{20 , 2 }, {10 , 1 }});
127+ EXPECT_EQ (group.asof_values , (std::vector<uint32_t > {10 , 20 }));
128+ group.sort_and_finalize ();
129+ EXPECT_EQ (group.asof_values , (std::vector<uint32_t > {10 , 20 }));
130+ EXPECT_EQ (group.row_indexes , (std::vector<uint32_t > {1 , 2 }));
131+ }
132+
116133TEST_F (AsofIndexGroupFinalizeTest, UInt64GroupsAreSupported) {
117134 auto group =
118135 make_group<uint64_t >({{30000000003ULL , 3 }, {10000000001ULL , 1 }, {20000000002ULL , 2 }});
@@ -123,6 +140,26 @@ TEST_F(AsofIndexGroupFinalizeTest, UInt64GroupsAreSupported) {
123140
124141class AsofIndexGroupBoundTest : public ::testing::Test {};
125142
143+ TEST_F (AsofIndexGroupBoundTest, EmptyGroupBoundReturnsZero) {
144+ AsofIndexGroup<uint32_t > group;
145+ group.sort_and_finalize ();
146+ EXPECT_EQ (group.lower_bound (42 ), 0U );
147+ EXPECT_EQ (group.upper_bound (42 ), 0U );
148+ }
149+
150+ TEST_F (AsofIndexGroupBoundTest, UInt64LowerAndUpperBound) {
151+ auto group = make_group<uint64_t >(
152+ {{10000000001ULL , 1 }, {20000000002ULL , 2 }, {20000000002ULL , 3 }, {40000000004ULL , 4 }});
153+ EXPECT_EQ (group.lower_bound (5000000000ULL ), 0U );
154+ EXPECT_EQ (group.upper_bound (5000000000ULL ), 0U );
155+ EXPECT_EQ (group.lower_bound (20000000002ULL ), 1U );
156+ EXPECT_EQ (group.upper_bound (20000000002ULL ), 3U );
157+ EXPECT_EQ (group.lower_bound (30000000000ULL ), 3U );
158+ EXPECT_EQ (group.upper_bound (30000000000ULL ), 3U );
159+ EXPECT_EQ (group.lower_bound (50000000000ULL ), 4U );
160+ EXPECT_EQ (group.upper_bound (50000000000ULL ), 4U );
161+ }
162+
126163TEST_F (AsofIndexGroupBoundTest, LowerAndUpperBoundRespectDuplicates) {
127164 auto group = make_group<uint32_t >({{10 , 1 }, {20 , 2 }, {20 , 3 }, {40 , 4 }});
128165 EXPECT_EQ (group.lower_bound (5 ), 0U );
@@ -215,6 +252,27 @@ TEST_F(AsofIndexGroupMatchTest, LargeGroupBinarySearch) {
215252 EXPECT_EQ ((large_group.template find_best_match <false , false >(1 )), 1U );
216253 EXPECT_EQ ((large_group.template find_best_match <false , false >(999 )), 500U );
217254 EXPECT_EQ ((large_group.template find_best_match <false , false >(2001 )), 0U );
255+
256+ EXPECT_EQ ((large_group.template find_best_match <true , true >(2 )), 0U );
257+ EXPECT_EQ ((large_group.template find_best_match <true , true >(500 )), 249U );
258+ EXPECT_EQ ((large_group.template find_best_match <true , true >(1000 )), 499U );
259+ EXPECT_EQ ((large_group.template find_best_match <true , true >(2000 )), 999U );
260+ EXPECT_EQ ((large_group.template find_best_match <true , true >(2001 )), 1000U );
261+
262+ EXPECT_EQ ((large_group.template find_best_match <false , true >(1 )), 1U );
263+ EXPECT_EQ ((large_group.template find_best_match <false , true >(2 )), 2U );
264+ EXPECT_EQ ((large_group.template find_best_match <false , true >(999 )), 500U );
265+ EXPECT_EQ ((large_group.template find_best_match <false , true >(2000 )), 0U );
266+ EXPECT_EQ ((large_group.template find_best_match <false , true >(2001 )), 0U );
267+ }
268+
269+ TEST_F (AsofIndexGroupMatchTest, EmptyGroupFindBestMatchReturnsZero) {
270+ AsofIndexGroup<uint32_t > empty_group;
271+ empty_group.sort_and_finalize ();
272+ EXPECT_EQ ((empty_group.template find_best_match <true , false >(42 )), 0U );
273+ EXPECT_EQ ((empty_group.template find_best_match <true , true >(42 )), 0U );
274+ EXPECT_EQ ((empty_group.template find_best_match <false , false >(42 )), 0U );
275+ EXPECT_EQ ((empty_group.template find_best_match <false , true >(42 )), 0U );
218276}
219277
220278TEST_F (AsofIndexGroupMatchTest, UInt64FindBestMatch) {
@@ -239,6 +297,34 @@ TEST_F(AsofColumnDispatchTest, DateV2Dispatch) {
239297 EXPECT_TRUE (dispatched_to_datev2);
240298}
241299
300+ TEST_F (AsofColumnDispatchTest, DateTimeV2Dispatch) {
301+ auto col = ColumnDateTimeV2::create ();
302+ uint64_t v1 = 1 , v2 = 2 ;
303+ col->insert_data (reinterpret_cast <const char *>(&v1), 0 );
304+ col->insert_data (reinterpret_cast <const char *>(&v2), 0 );
305+ bool dispatched_to_dtv2 = false ;
306+ asof_column_dispatch (col.get (), [&](const auto * typed_col) {
307+ if constexpr (std::is_same_v<std::decay_t <decltype (*typed_col)>, ColumnDateTimeV2>) {
308+ dispatched_to_dtv2 = true ;
309+ }
310+ });
311+ EXPECT_TRUE (dispatched_to_dtv2);
312+ }
313+
314+ TEST_F (AsofColumnDispatchTest, TimestampTZDispatch) {
315+ auto col = ColumnTimeStampTz::create ();
316+ uint64_t v1 = 1 , v2 = 2 ;
317+ col->insert_data (reinterpret_cast <const char *>(&v1), 0 );
318+ col->insert_data (reinterpret_cast <const char *>(&v2), 0 );
319+ bool dispatched_to_tstz = false ;
320+ asof_column_dispatch (col.get (), [&](const auto * typed_col) {
321+ if constexpr (std::is_same_v<std::decay_t <decltype (*typed_col)>, ColumnTimeStampTz>) {
322+ dispatched_to_tstz = true ;
323+ }
324+ });
325+ EXPECT_TRUE (dispatched_to_tstz);
326+ }
327+
242328TEST_F (AsofColumnDispatchTest, FallbackDispatch) {
243329 auto col = make_int32_column ({1 , 2 , 3 });
244330 bool dispatched_to_icol = false ;
@@ -250,4 +336,52 @@ TEST_F(AsofColumnDispatchTest, FallbackDispatch) {
250336 EXPECT_TRUE (dispatched_to_icol);
251337}
252338
339+ class AsofJoinHelperTest : public ::testing::Test {};
340+
341+ TEST_F (AsofJoinHelperTest, IsAsofJoinRuntime) {
342+ EXPECT_TRUE (is_asof_join (TJoinOp::ASOF_LEFT_INNER_JOIN));
343+ EXPECT_TRUE (is_asof_join (TJoinOp::ASOF_LEFT_OUTER_JOIN));
344+ EXPECT_FALSE (is_asof_join (TJoinOp::INNER_JOIN));
345+ EXPECT_FALSE (is_asof_join (TJoinOp::LEFT_OUTER_JOIN));
346+ }
347+
348+ TEST_F (AsofJoinHelperTest, IsAsofJoinCompileTime) {
349+ static_assert (is_asof_join_op_v<TJoinOp::ASOF_LEFT_INNER_JOIN>);
350+ static_assert (is_asof_join_op_v<TJoinOp::ASOF_LEFT_OUTER_JOIN>);
351+ static_assert (!is_asof_join_op_v<TJoinOp::INNER_JOIN>);
352+ static_assert (!is_asof_join_op_v<TJoinOp::LEFT_OUTER_JOIN>);
353+
354+ static_assert (!is_asof_outer_join_op_v<TJoinOp::ASOF_LEFT_INNER_JOIN>);
355+ static_assert (is_asof_outer_join_op_v<TJoinOp::ASOF_LEFT_OUTER_JOIN>);
356+ static_assert (!is_asof_outer_join_op_v<TJoinOp::INNER_JOIN>);
357+ }
358+
359+ class AsofIndexVariantTest : public ::testing::Test {};
360+
361+ TEST_F (AsofIndexVariantTest, MonostateIsDefault) {
362+ AsofIndexVariant variant;
363+ EXPECT_TRUE (std::holds_alternative<std::monostate>(variant));
364+ }
365+
366+ TEST_F (AsofIndexVariantTest, EmplaceUint32Groups) {
367+ AsofIndexVariant variant;
368+ auto & groups = variant.emplace <std::vector<AsofIndexGroup<uint32_t >>>();
369+ groups.emplace_back ();
370+ groups[0 ].add_row (10 , 1 );
371+ groups[0 ].sort_and_finalize ();
372+ EXPECT_TRUE (std::holds_alternative<std::vector<AsofIndexGroup<uint32_t >>>(variant));
373+ EXPECT_EQ (std::get<std::vector<AsofIndexGroup<uint32_t >>>(variant)[0 ].asof_values [0 ], 10U );
374+ }
375+
376+ TEST_F (AsofIndexVariantTest, EmplaceUint64Groups) {
377+ AsofIndexVariant variant;
378+ auto & groups = variant.emplace <std::vector<AsofIndexGroup<uint64_t >>>();
379+ groups.emplace_back ();
380+ groups[0 ].add_row (99999999999ULL , 1 );
381+ groups[0 ].sort_and_finalize ();
382+ EXPECT_TRUE (std::holds_alternative<std::vector<AsofIndexGroup<uint64_t >>>(variant));
383+ EXPECT_EQ (std::get<std::vector<AsofIndexGroup<uint64_t >>>(variant)[0 ].asof_values [0 ],
384+ 99999999999ULL );
385+ }
386+
253387} // namespace doris
0 commit comments