Skip to content

Commit 7f14cf7

Browse files
authored
Merge branch 'main' into spill-pr1
2 parents 3b264f3 + f6562e6 commit 7f14cf7

13 files changed

Lines changed: 577 additions & 61 deletions

File tree

include/paimon/predicate/literal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ class PAIMON_EXPORT Literal {
3737
explicit Literal(FieldType type);
3838

3939
/// Creates a literal from a typed value.
40-
/// The template parameter T must be compatible with one of the supported field types.
41-
/// @tparam T The C++ type of the value (must match a supported FieldType).
40+
/// The template parameter T must be compatible with one of the supported field types
41+
/// (must match a supported FieldType).
42+
/// T can be bool, int8_t, int16_t, int32_t, int64_t, float, double, Timestamp and Decimal.
4243
/// @param val The value to store in the literal.
4344
template <typename T>
4445
explicit Literal(const T& val);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2026-present Alibaba Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <cstdint>
20+
#include <vector>
21+
22+
#include "paimon/result.h"
23+
#include "paimon/utils/range.h"
24+
#include "paimon/visibility.h"
25+
26+
namespace paimon {
27+
28+
/// Index for row ranges. Provides efficient intersection queries over a sorted, non-overlapping
29+
/// collection of ranges using binary search.
30+
class PAIMON_EXPORT RowRangeIndex {
31+
public:
32+
/// Creates a RowRangeIndex from the given ranges. The ranges will be sorted and merged
33+
/// (overlapping and adjacent ranges are combined) before indexing.
34+
static Result<RowRangeIndex> Create(const std::vector<Range>& ranges);
35+
36+
/// Returns the sorted, non-overlapping ranges held by this index.
37+
const std::vector<Range>& Ranges() const;
38+
39+
/// Returns true if any range in this index intersects with the interval [start, end].
40+
bool Intersects(int64_t start, int64_t end) const;
41+
42+
/// Returns the sub-ranges of this index that intersect with the interval [start, end].
43+
/// Each returned range is clipped to lie within [start, end].
44+
std::vector<Range> IntersectedRanges(int64_t start, int64_t end) const;
45+
46+
private:
47+
explicit RowRangeIndex(std::vector<Range> ranges);
48+
49+
/// Finds the first index in `ends_` whose value is >= target (lower bound).
50+
int32_t LowerBound(int64_t target) const;
51+
52+
private:
53+
std::vector<Range> ranges_;
54+
std::vector<int64_t> starts_;
55+
std::vector<int64_t> ends_;
56+
};
57+
58+
} // namespace paimon

src/paimon/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ set(PAIMON_COMMON_SRCS
142142
common/utils/byte_range_combiner.cpp
143143
common/utils/roaring_bitmap32.cpp
144144
common/utils/roaring_bitmap64.cpp
145+
common/utils/row_range_index.cpp
145146
common/utils/status.cpp
146147
common/utils/string_utils.cpp)
147148

@@ -455,6 +456,7 @@ if(PAIMON_BUILD_TESTS)
455456
common/types/data_type_json_parser_test.cpp
456457
common/types/row_kind_test.cpp
457458
common/types/data_type_test.cpp
459+
common/utils/row_range_index_test.cpp
458460
common/utils/var_length_int_utils_test.cpp
459461
common/utils/arrow/arrow_utils_test.cpp
460462
common/utils/arrow/arrow_stream_adapter_test.cpp
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2026-present Alibaba Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "paimon/utils/row_range_index.h"
18+
19+
#include <algorithm>
20+
#include <cassert>
21+
22+
namespace paimon {
23+
24+
RowRangeIndex::RowRangeIndex(std::vector<Range> ranges) : ranges_(std::move(ranges)) {
25+
starts_.reserve(ranges_.size());
26+
ends_.reserve(ranges_.size());
27+
for (const auto& range : ranges_) {
28+
starts_.push_back(range.from);
29+
ends_.push_back(range.to);
30+
}
31+
}
32+
33+
Result<RowRangeIndex> RowRangeIndex::Create(const std::vector<Range>& ranges) {
34+
if (ranges.empty()) {
35+
return Status::Invalid("Ranges cannot be empty in RowRangeIndex");
36+
}
37+
return RowRangeIndex(Range::SortAndMergeOverlap(ranges, /*adjacent=*/true));
38+
}
39+
40+
const std::vector<Range>& RowRangeIndex::Ranges() const {
41+
return ranges_;
42+
}
43+
44+
bool RowRangeIndex::Intersects(int64_t start, int64_t end) const {
45+
int32_t candidate = LowerBound(start);
46+
return candidate < static_cast<int32_t>(starts_.size()) && starts_[candidate] <= end;
47+
}
48+
49+
std::vector<Range> RowRangeIndex::IntersectedRanges(int64_t start, int64_t end) const {
50+
int32_t left = LowerBound(start);
51+
if (left >= static_cast<int32_t>(ranges_.size())) {
52+
return {};
53+
}
54+
55+
int32_t right = LowerBound(end);
56+
if (right >= static_cast<int32_t>(ranges_.size())) {
57+
right = static_cast<int32_t>(ranges_.size()) - 1;
58+
}
59+
60+
if (starts_[left] > end) {
61+
return {};
62+
}
63+
64+
std::vector<Range> expected;
65+
66+
// Add the first intersecting range, clipped to [start, end].
67+
const Range& first_range = ranges_[left];
68+
expected.emplace_back(std::max(start, first_range.from), std::min(end, first_range.to));
69+
70+
// Add all fully contained ranges between first and last.
71+
for (int32_t i = left + 1; i < right; ++i) {
72+
expected.push_back(ranges_[i]);
73+
}
74+
75+
// Add the last intersecting range (if different from the first), clipped to [start, end].
76+
if (right != left) {
77+
const Range& last_range = ranges_[right];
78+
if (last_range.from <= end) {
79+
expected.emplace_back(std::max(start, last_range.from), std::min(end, last_range.to));
80+
}
81+
}
82+
83+
return expected;
84+
}
85+
86+
int32_t RowRangeIndex::LowerBound(int64_t target) const {
87+
int32_t left = 0;
88+
auto right = static_cast<int32_t>(ends_.size());
89+
while (left < right) {
90+
int32_t mid = left + (right - left) / 2;
91+
if (ends_[mid] < target) {
92+
left = mid + 1;
93+
} else {
94+
right = mid;
95+
}
96+
}
97+
return left;
98+
}
99+
100+
} // namespace paimon

0 commit comments

Comments
 (0)