Coverage Report

Created: 2026-03-13 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/predicate/null_predicate.h
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
#pragma once
19
20
#include <glog/logging.h>
21
#include <stdint.h>
22
23
#include <ostream>
24
#include <string>
25
#include <utility>
26
27
#include "common/status.h"
28
#include "format/parquet/parquet_predicate.h"
29
#include "storage/index/bloom_filter/bloom_filter.h"
30
#include "storage/predicate/column_predicate.h"
31
#include "storage/schema.h"
32
33
namespace roaring {
34
class Roaring;
35
} // namespace roaring
36
37
namespace doris {
38
namespace segment_v2 {
39
class InvertedIndexIterator;
40
} // namespace segment_v2
41
class IColumn;
42
43
class NullPredicate final : public ColumnPredicate {
44
public:
45
    ENABLE_FACTORY_CREATOR(NullPredicate);
46
    NullPredicate(uint32_t column_id, std::string col_name, bool is_null, PrimitiveType type,
47
                  bool opposite = false);
48
    NullPredicate(const NullPredicate& other) = delete;
49
    NullPredicate(const NullPredicate& other, uint32_t column_id)
50
2.71k
            : ColumnPredicate(other, column_id), _is_null(other._is_null) {}
51
    ~NullPredicate() override = default;
52
2.73k
    std::shared_ptr<ColumnPredicate> clone(uint32_t column_id) const override {
53
2.73k
        return NullPredicate::create_shared(*this, column_id);
54
2.73k
    }
55
1.08k
    std::string debug_string() const override {
56
1.08k
        fmt::memory_buffer debug_string_buffer;
57
1.08k
        fmt::format_to(debug_string_buffer, "NullPredicate({}, is_null={})",
58
1.08k
                       ColumnPredicate::debug_string(), _is_null);
59
1.08k
        return fmt::to_string(debug_string_buffer);
60
1.08k
    }
61
341
    bool could_be_erased() const override { return true; }
62
63
    PredicateType type() const override;
64
65
    Status evaluate(const IndexFieldNameAndTypePair& name_with_type, IndexIterator* iterator,
66
                    uint32_t num_rows, roaring::Roaring* bitmap) const override;
67
68
    void evaluate_or(const IColumn& column, const uint16_t* sel, uint16_t size,
69
                     bool* flags) const override;
70
71
    void evaluate_and(const IColumn& column, const uint16_t* sel, uint16_t size,
72
                      bool* flags) const override;
73
74
5.32k
    bool evaluate_and(const segment_v2::ZoneMap& zone_map) const override {
75
5.32k
        if (_is_null) {
76
4.43k
            return zone_map.has_null;
77
4.43k
        } else {
78
891
            return zone_map.has_not_null;
79
891
        }
80
5.32k
    }
81
82
865
    bool evaluate_and(ParquetPredicate::ColumnStat* statistic) const override {
83
865
        if (!(*statistic->get_stat_func)(statistic, column_id())) {
84
314
            return true;
85
314
        }
86
551
        if (_is_null) {
87
117
            return true;
88
434
        } else {
89
434
            return !statistic->is_all_null;
90
434
        }
91
551
    }
92
93
    bool evaluate_and(ParquetPredicate::CachedPageIndexStat* statistic,
94
138
                      RowRanges* row_ranges) const override {
95
138
        ParquetPredicate::PageIndexStat* stat = nullptr;
96
138
        if (!(statistic->get_stat_func)(&stat, column_id())) {
97
0
            row_ranges->add(statistic->row_group_range);
98
0
            return true;
99
0
        }
100
1.07k
        for (int page_id = 0; page_id < stat->num_of_pages; page_id++) {
101
936
            if (_is_null || !stat->is_all_null[page_id]) {
102
936
                row_ranges->add(stat->ranges[page_id]);
103
936
            }
104
936
        };
105
138
        return row_ranges->count() > 0;
106
138
    }
107
108
2
    bool evaluate_del(const segment_v2::ZoneMap& zone_map) const override {
109
        // evaluate_del only use for delete condition to filter page, need use delete condition origin value,
110
        // when opposite==true, origin value 'is null'->'is not null' and 'is not null'->'is null',
111
        // so when _is_null==true, need check 'is not null' and _is_null==false, need check 'is null'
112
2
        if (_is_null) {
113
1
            return !zone_map.has_null;
114
1
        } else {
115
1
            return !zone_map.has_not_null;
116
1
        }
117
2
    }
118
119
0
    bool evaluate_and(const segment_v2::BloomFilter* bf) const override {
120
        // null predicate can not use ngram bf, just return true to accept
121
0
        if (bf->is_ngram_bf()) return true;
122
0
        if (_is_null) {
123
0
            return bf->test_bytes(nullptr, 0);
124
0
        } else {
125
0
            throw Exception(Status::FatalError(
126
0
                    "Bloom filter is not supported by predicate type: is_null="));
127
0
        }
128
0
    }
129
130
3.65k
    bool can_do_bloom_filter(bool ngram) const override { return _is_null && !ngram; }
131
132
    void evaluate_vec(const IColumn& column, uint16_t size, bool* flags) const override;
133
134
private:
135
    uint16_t _evaluate_inner(const IColumn& column, uint16_t* sel, uint16_t size) const override;
136
137
    bool _is_null; //true for null, false for not null
138
};
139
140
} //namespace doris