Coverage Report

Created: 2026-07-12 22:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format_v2/expr/delete_predicate.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_v2/expr/delete_predicate.h"
19
20
#include <fmt/format.h>
21
#include <gen_cpp/Exprs_types.h>
22
#include <glog/logging.h>
23
24
#include <algorithm>
25
#include <cstddef>
26
#include <ostream>
27
28
#include "common/cast_set.h"
29
#include "common/status.h"
30
#include "core/block/block.h"
31
#include "core/block/column_numbers.h"
32
#include "core/block/column_with_type_and_name.h"
33
#include "core/block/columns_with_type_and_name.h"
34
35
namespace doris::format {
36
37
DeletePredicate::DeletePredicate(const std::vector<int64_t>& deleted_rows)
38
23
        : VExpr(), _deleted_rows(&deleted_rows) {
39
23
    _node_type = TExprNodeType::PREDICATE;
40
23
    _opcode = TExprOpcode::DELETE;
41
23
    _data_type = std::make_shared<DataTypeBool>();
42
23
}
43
44
DeletePredicate::DeletePredicate(const roaring::Roaring64Map& deletion_vector)
45
5
        : VExpr(), _deletion_vector(&deletion_vector) {
46
5
    _node_type = TExprNodeType::PREDICATE;
47
5
    _opcode = TExprOpcode::DELETE;
48
5
    _data_type = std::make_shared<DataTypeBool>();
49
5
}
50
51
Status DeletePredicate::prepare(RuntimeState* state, const RowDescriptor& desc,
52
11
                                VExprContext* context) {
53
11
    RETURN_IF_ERROR_OR_PREPARED(VExpr::prepare(state, desc, context));
54
11
    _expr_name = "DeletePredicate";
55
11
    _prepare_finished = true;
56
11
    return Status::OK();
57
11
}
58
59
Status DeletePredicate::open(RuntimeState* state, VExprContext* context,
60
11
                             FunctionContext::FunctionStateScope scope) {
61
11
    DCHECK(_prepare_finished);
62
11
    RETURN_IF_ERROR_OR_PREPARED(VExpr::open(state, context, scope));
63
0
    _open_finished = true;
64
0
    return Status::OK();
65
0
}
66
67
11
void DeletePredicate::close(VExprContext* context, FunctionContext::FunctionStateScope scope) {
68
11
    VExpr::close(context, scope);
69
11
}
70
71
/**
72
 * DeletePredicate is derived from 2 cases:
73
 * 1. All row IDs indicates deleted rows. (e.g. Delete rows with row_id in (1, 2, 3))
74
 * 2. Bit vector indicates whether each row is deleted or not. (e.g. Bit vector[0,1,0,0,1] indicates row 1 and row 4 are deleted)
75
 *
76
 * So DeletePredicate should have exactly 1 child expr, which is the slot of row id.
77
 * Row IDs should be generated by file reader as a virtual column in `block`.
78
 **/
79
24
Status DeletePredicate::execute(VExprContext* context, Block* block, int* result_column_id) const {
80
24
    if (_children.size() != 1) {
81
1
        return Status::InternalError(fmt::format(
82
1
                "DeletePredicate should have exactly 1 child expr, but got {}", _children.size()));
83
1
    }
84
23
    int slot = -1;
85
23
    RETURN_IF_ERROR(_children[0]->execute(context, block, &slot));
86
23
    if (slot < 0 || static_cast<size_t>(slot) >= block->columns()) {
87
1
        return Status::InternalError(
88
1
                "DeletePredicate row id child returned invalid column id {}, block has {} columns",
89
1
                slot, block->columns());
90
1
    }
91
22
    const auto& row_ids =
92
22
            assert_cast<const ColumnInt64&>(*block->get_by_position(slot).column).get_data();
93
22
    const auto count = row_ids.size();
94
22
    auto res_col = ColumnBool::create(count, 0);
95
22
    if ((_deleted_rows == nullptr || _deleted_rows->empty()) &&
96
22
        (_deletion_vector == nullptr || _deletion_vector->isEmpty())) {
97
1
        block->insert({std::move(res_col), std::make_shared<DataTypeBool>(), expr_name()});
98
1
        *result_column_id = static_cast<int>(block->get_columns().size() - 1);
99
1
        return Status::OK();
100
1
    }
101
21
    if (count == 0) {
102
1
        block->insert({std::move(res_col), std::make_shared<DataTypeBool>(), expr_name()});
103
1
        *result_column_id = static_cast<int>(block->get_columns().size() - 1);
104
1
        return Status::OK();
105
1
    }
106
20
    if (_deletion_vector != nullptr) {
107
5
        auto it = _deletion_vector->begin();
108
5
        it.move(cast_set<uint64_t>(row_ids[0]));
109
5
        const auto end = _deletion_vector->end();
110
5
        const auto last_row_id = cast_set<uint64_t>(row_ids[count - 1]);
111
15
        while (it != end && *it <= last_row_id) {
112
10
            const auto row = cast_set<int64_t>(*it);
113
10
            if (const auto row_it = std::ranges::lower_bound(row_ids, row);
114
10
                row_it != row_ids.end() && *row_it == row) {
115
10
                res_col->get_data()[row_it - row_ids.begin()] = true;
116
10
            }
117
10
            ++it;
118
10
        }
119
5
        block->insert({std::move(res_col), std::make_shared<DataTypeBool>(), expr_name()});
120
5
        *result_column_id = static_cast<int>(block->get_columns().size() - 1);
121
5
        return Status::OK();
122
5
    }
123
124
15
    const int64_t* delete_rows = _deleted_rows->data();
125
15
    const int64_t* delete_rows_end = delete_rows + _deleted_rows->size();
126
15
    const int64_t* start_pos = std::lower_bound(delete_rows, delete_rows_end, row_ids[0]);
127
15
    int64_t start_index = start_pos - delete_rows;
128
15
    const int64_t* end_pos = std::upper_bound(start_pos, delete_rows_end, row_ids[count - 1]);
129
15
    const int64_t end_index = end_pos - delete_rows;
130
131
36
    while (start_index < end_index) {
132
21
        int64_t delete_row = delete_rows[start_index];
133
21
        if (const auto it = std::ranges::lower_bound(row_ids, delete_row);
134
21
            it != row_ids.end() && *it == delete_row) {
135
21
            const size_t index = it - row_ids.begin();
136
21
            res_col->get_data()[index] = true;
137
21
        }
138
21
        ++start_index;
139
21
    }
140
15
    block->insert({std::move(res_col), std::make_shared<DataTypeBool>(), expr_name()});
141
15
    *result_column_id = static_cast<int>(block->get_columns().size() - 1);
142
15
    return Status::OK();
143
20
}
144
145
1
std::string DeletePredicate::debug_string() const {
146
1
    return _expr_name;
147
1
}
148
149
} // namespace doris::format