Coverage Report

Created: 2026-04-11 13:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/table/equality_delete.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "format/table/equality_delete.h"
19
20
#include "exprs/create_predicate_function.h"
21
22
namespace doris {
23
24
std::unique_ptr<EqualityDeleteBase> EqualityDeleteBase::get_delete_impl(
25
1.70k
        const Block* delete_block, const std::vector<int>& delete_col_ids) {
26
1.70k
    DCHECK_EQ(delete_block->columns(), delete_col_ids.size());
27
1.70k
    if (delete_block->columns() == 1) {
28
776
        return std::make_unique<SimpleEqualityDelete>(delete_block, delete_col_ids);
29
928
    } else {
30
928
        return std::make_unique<MultiEqualityDelete>(delete_block, delete_col_ids);
31
928
    }
32
1.70k
}
33
34
776
Status SimpleEqualityDelete::_build_set() {
35
776
    COUNTER_UPDATE(num_delete_rows, _delete_block->rows());
36
776
    if (_delete_block->columns() != 1) [[unlikely]] {
37
0
        return Status::InternalError("Simple equality delete can be only applied with one column");
38
0
    }
39
776
    auto& column_and_type = _delete_block->get_by_position(0);
40
776
    auto delete_column_type = remove_nullable(column_and_type.type)->get_primitive_type();
41
776
    _hybrid_set.reset(create_set(delete_column_type, _delete_block->rows(), false));
42
776
    _hybrid_set->insert_fixed_len(column_and_type.column, 0);
43
776
    return Status::OK();
44
776
}
45
46
Status SimpleEqualityDelete::filter_data_block(
47
        Block* data_block, const std::unordered_map<std::string, uint32_t>* col_name_to_block_idx,
48
        const std::unordered_map<int, std::string>& id_to_block_column_name,
49
1.13k
        IColumn::Filter& filter) {
50
1.13k
    SCOPED_TIMER(equality_delete_time);
51
1.13k
    DCHECK(_delete_col_ids.size() == 1);
52
1.13k
    auto column_field_id = _delete_col_ids[0];
53
54
1.13k
    auto column_and_type = data_block->get_by_position(
55
1.13k
            col_name_to_block_idx->at(id_to_block_column_name.at(column_field_id)));
56
57
1.13k
    size_t rows = data_block->rows();
58
    //     _filter: 1 => in _hybrid_set; 0 => not in _hybrid_set
59
1.13k
    if (_single_filter == nullptr) {
60
776
        _single_filter = std::make_unique<IColumn::Filter>(rows, 0);
61
776
    } else {
62
        // reset the array capacity and fill all elements using the 0
63
354
        _single_filter->assign(rows, UInt8(0));
64
354
    }
65
1.13k
    if (column_and_type.column->is_nullable()) {
66
1.13k
        const NullMap& null_map =
67
1.13k
                reinterpret_cast<const ColumnNullable*>(column_and_type.column.get())
68
1.13k
                        ->get_null_map_data();
69
1.13k
        _hybrid_set->find_batch_nullable(
70
1.13k
                remove_nullable(column_and_type.column)->assume_mutable_ref(), rows, null_map,
71
1.13k
                *_single_filter);
72
1.13k
        if (_hybrid_set->contain_null()) {
73
0
            auto* filter_data = _single_filter->data();
74
0
            for (size_t i = 0; i < rows; ++i) {
75
0
                filter_data[i] = filter_data[i] || null_map[i];
76
0
            }
77
0
        }
78
1.13k
    } else {
79
0
        _hybrid_set->find_batch(column_and_type.column->assume_mutable_ref(), rows,
80
0
                                *_single_filter);
81
0
    }
82
    // should reverse _filter
83
1.13k
    auto* filter_data = filter.data();
84
2.52k
    for (size_t i = 0; i < rows; ++i) {
85
1.39k
        filter_data[i] &= !_single_filter->data()[i];
86
1.39k
    }
87
1.13k
    return Status::OK();
88
1.13k
}
89
90
928
Status MultiEqualityDelete::_build_set() {
91
928
    COUNTER_UPDATE(num_delete_rows, _delete_block->rows());
92
928
    size_t rows = _delete_block->rows();
93
928
    _delete_hashes.clear();
94
928
    _delete_hashes.resize(rows, 0);
95
1.88k
    for (ColumnPtr column : _delete_block->get_columns()) {
96
1.88k
        column->update_hashes_with_value(_delete_hashes.data(), nullptr);
97
1.88k
    }
98
3.60k
    for (size_t i = 0; i < rows; ++i) {
99
2.68k
        _delete_hash_map.insert({_delete_hashes[i], i});
100
2.68k
    }
101
928
    _data_column_index.resize(_delete_block->columns());
102
928
    return Status::OK();
103
928
}
104
105
Status MultiEqualityDelete::filter_data_block(
106
        Block* data_block, const std::unordered_map<std::string, uint32_t>* col_name_to_block_idx,
107
        const std::unordered_map<int, std::string>& id_to_block_column_name,
108
1.35k
        IColumn::Filter& filter) {
109
1.35k
    SCOPED_TIMER(equality_delete_time);
110
1.35k
    DCHECK_EQ(_delete_block->get_columns_with_type_and_name().size(), _delete_col_ids.size());
111
1.35k
    size_t column_index = 0;
112
113
4.10k
    for (size_t idx = 0; idx < _delete_block->get_columns_with_type_and_name().size(); ++idx) {
114
2.74k
        auto delete_col = _delete_block->get_columns_with_type_and_name()[idx];
115
2.74k
        auto delete_col_id = _delete_col_ids[idx];
116
117
2.74k
        DCHECK(id_to_block_column_name.contains(delete_col_id));
118
2.74k
        const auto& block_column_name = id_to_block_column_name.at(delete_col_id);
119
2.74k
        if (!col_name_to_block_idx->contains(block_column_name)) [[unlikely]] {
120
0
            return Status::InternalError("Column '{}' not found in data block: {}",
121
0
                                         block_column_name, data_block->dump_structure());
122
0
        }
123
2.74k
        auto column_and_type =
124
2.74k
                data_block->safe_get_by_position(col_name_to_block_idx->at(block_column_name));
125
2.74k
        if (!delete_col.type->equals(*column_and_type.type)) [[unlikely]] {
126
0
            return Status::InternalError(
127
0
                    "Not support type change in column '{}', src type: {}, target type: {}",
128
0
                    block_column_name, delete_col.type->get_name(),
129
0
                    column_and_type.type->get_name());
130
0
        }
131
2.74k
        _data_column_index[column_index++] = col_name_to_block_idx->at(block_column_name);
132
2.74k
    }
133
1.35k
    size_t rows = data_block->rows();
134
1.35k
    _data_hashes.clear();
135
1.35k
    _data_hashes.resize(rows, 0);
136
2.74k
    for (size_t index : _data_column_index) {
137
2.74k
        data_block->get_by_position(index).column->update_hashes_with_value(_data_hashes.data(),
138
2.74k
                                                                            nullptr);
139
2.74k
    }
140
1.35k
    auto* filter_data = filter.data();
141
3.00k
    for (size_t i = 0; i < rows; ++i) {
142
1.64k
        for (auto beg = _delete_hash_map.lower_bound(_data_hashes[i]),
143
1.64k
                  end = _delete_hash_map.upper_bound(_data_hashes[i]);
144
1.89k
             beg != end; ++beg) {
145
976
            if (filter[i] && _equal(data_block, i, beg->second)) {
146
732
                filter_data[i] = 0;
147
732
                break;
148
732
            }
149
976
        }
150
1.64k
    }
151
152
1.35k
    return Status::OK();
153
1.35k
}
154
155
bool MultiEqualityDelete::_equal(Block* data_block, size_t data_row_index,
156
732
                                 size_t delete_row_index) {
157
2.22k
    for (size_t i = 0; i < _delete_block->columns(); ++i) {
158
1.48k
        ColumnPtr data_col = data_block->get_by_position(_data_column_index[i]).column;
159
1.48k
        ColumnPtr delete_col = _delete_block->get_by_position(i).column;
160
1.48k
        if (data_col->compare_at(data_row_index, delete_row_index, *delete_col, -1) != 0) {
161
0
            return false;
162
0
        }
163
1.48k
    }
164
732
    return true;
165
732
}
166
167
} // namespace doris