Coverage Report

Created: 2026-11-02 21:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/raw_value.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
// This file is copied from
18
// https://github.com/apache/impala/blob/branch-2.9.0/be/src/runtime/raw-value.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <string>
24
25
#include "common/check.h"
26
#include "common/consts.h"
27
#include "common/exception.h"
28
#include "common/logging.h"
29
#include "core/data_type/define_primitive_type.h"
30
#include "core/packed_int128.h"
31
#include "core/string_ref.h"
32
#include "util/hash_util.hpp"
33
34
namespace doris {
35
class SlotDescriptor;
36
37
// Useful utility functions for runtime values (which are passed around as void*).
38
class RawValue {
39
public:
40
    // Same as the up function, only use in vec exec engine.
41
    static uint32_t zlib_crc32(const void* value, size_t len, const PrimitiveType& type,
42
                               uint32_t seed);
43
44
    // Treat the canonical distribution bytes of a value as an unsigned integer with the first byte
45
    // as the least-significant byte, then append it to the preceding distribution columns. The
46
    // returned value is kept modulo mod throughout, so values of any byte width and any number of
47
    // columns do not require a wide integer.
48
    static uint32_t identity_hash(const void* value, size_t len, const PrimitiveType& type,
49
                                  uint32_t seed, uint32_t mod);
50
51
    // The single appending core shared by identity_hash and the batch column implementations in
52
    // IColumn::update_identity_hash. Interprets size bytes as a little-endian unsigned integer,
53
    // multiplies the seed by 256^size and adds the value, taking mod every 4 bytes so any byte
54
    // width never overflows uint64_t. This is the sole source of the identity hash byte semantics
55
    // and must stay bit-identical with FE HashDistributionPruner and BE tablet routing.
56
    static uint32_t append_identity_bytes(const void* value, size_t size, uint32_t seed,
57
                                          uint32_t mod);
58
59
    // A null distribution value contributes these four zero canonical bytes, shared by the
60
    // scalar and batch paths so the null convention has a single definition.
61
    static constexpr uint32_t NULL_IDENTITY_BYTES = 0;
62
};
63
64
// Keep the canonical byte-width dispatch together so it can be audited against zlib_crc32 below.
65
// NOLINTNEXTLINE(readability-function-size)
66
inline uint32_t RawValue::append_identity_bytes(const void* value, size_t size, uint32_t seed,
67
1.19M
                                                uint32_t mod) {
68
1.19M
    DCHECK_GT(mod, 0);
69
1.19M
    const auto* bytes = reinterpret_cast<const uint8_t*>(value);
70
1.19M
    uint64_t remainder = seed;
71
1.19M
    size_t bytes_since_mod = 0;
72
6.03M
    for (size_t i = size; i > 0; --i) {
73
4.83M
        remainder = remainder * 256 + bytes[i - 1];
74
4.83M
        if (++bytes_since_mod == sizeof(uint32_t)) {
75
1.20M
            remainder %= mod;
76
1.20M
            bytes_since_mod = 0;
77
1.20M
        }
78
4.83M
    }
79
1.19M
    return static_cast<uint32_t>(remainder % mod);
80
1.19M
}
81
82
// NOLINTNEXTLINE(readability-function-size)
83
inline uint32_t RawValue::identity_hash(const void* v, size_t len, const PrimitiveType& type,
84
1.19M
                                        uint32_t seed, uint32_t mod) {
85
1.19M
    DCHECK_GT(mod, 0);
86
1.19M
    auto append_little_endian = [&seed, mod](const void* value, size_t size) {
87
1.19M
        seed = append_identity_bytes(value, size, seed, mod);
88
1.19M
    };
89
90
1.19M
    if (v == nullptr) {
91
837
        append_little_endian(&NULL_IDENTITY_BYTES, sizeof(NULL_IDENTITY_BYTES));
92
837
        return seed;
93
837
    }
94
95
1.19M
    switch (type) {
96
25
    case TYPE_VARCHAR:
97
25
    case TYPE_VARBINARY:
98
25
    case TYPE_HLL:
99
52
    case TYPE_STRING:
100
56
    case TYPE_CHAR:
101
56
        append_little_endian(v, len);
102
56
        break;
103
22
    case TYPE_BOOLEAN:
104
44
    case TYPE_TINYINT:
105
44
        append_little_endian(v, 1);
106
44
        break;
107
22
    case TYPE_SMALLINT:
108
22
        append_little_endian(v, 2);
109
22
        break;
110
1.18M
    case TYPE_INT:
111
1.18M
    case TYPE_FLOAT:
112
1.18M
    case TYPE_DATEV2:
113
1.18M
    case TYPE_DECIMAL32:
114
1.18M
    case TYPE_IPV4:
115
1.18M
        append_little_endian(v, 4);
116
1.18M
        break;
117
8.55k
    case TYPE_BIGINT:
118
8.56k
    case TYPE_DOUBLE:
119
8.58k
    case TYPE_TIMEV2:
120
8.61k
    case TYPE_DATETIMEV2:
121
8.64k
    case TYPE_TIMESTAMP_NS:
122
8.66k
    case TYPE_TIMESTAMPTZ:
123
8.70k
    case TYPE_DECIMAL64:
124
8.70k
        append_little_endian(v, 8);
125
8.70k
        break;
126
31
    case TYPE_LARGEINT:
127
49
    case TYPE_DECIMAL128I:
128
72
    case TYPE_IPV6:
129
82
    case TYPE_UUID:
130
82
        append_little_endian(v, 16);
131
82
        break;
132
28
    case TYPE_DECIMAL256:
133
28
        append_little_endian(v, 32);
134
28
        break;
135
30
    case TYPE_DATE:
136
39
    case TYPE_DATETIME: {
137
39
        const auto* date_val = reinterpret_cast<const VecDateTimeValue*>(v);
138
39
        char buf[64];
139
39
        int date_len = date_val->to_buffer(buf);
140
39
        append_little_endian(buf, date_len);
141
39
        break;
142
30
    }
143
27
    case TYPE_DECIMALV2: {
144
27
        const auto* dec_val = reinterpret_cast<const DecimalV2Value*>(v);
145
27
        int64_t int_val = dec_val->int_value();
146
27
        int32_t frac_val = dec_val->frac_value();
147
27
        append_little_endian(&frac_val, sizeof(frac_val));
148
27
        append_little_endian(&int_val, sizeof(int_val));
149
27
        break;
150
30
    }
151
0
    default:
152
0
        DORIS_CHECK(false) << "invalid type: " << type;
153
1.19M
    }
154
1.19M
    return seed;
155
1.19M
}
156
157
// NOTE: this is just for split data, decimal use old doris hash function
158
// Because crc32 hardware is not equal with zlib crc32
159
inline uint32_t RawValue::zlib_crc32(const void* v, size_t len, const PrimitiveType& type,
160
40.9M
                                     uint32_t seed) {
161
    // Reject binary even for NULL instead of reaching the default-type assertion or hash path.
162
40.9M
    if (type == TYPE_VARBINARY) {
163
3
        throw Exception(ErrorCode::NOT_IMPLEMENTED_ERROR,
164
3
                        "VARBINARY tablet routing hash is not supported");
165
3
    }
166
    // Hash_combine with v = 0
167
40.9M
    if (v == nullptr) {
168
0
        uint32_t value = 0x9e3779b9;
169
0
        return seed ^ (value + (seed << 6) + (seed >> 2));
170
0
    }
171
172
40.9M
    switch (type) {
173
968k
    case TYPE_VARCHAR:
174
968k
    case TYPE_HLL:
175
968k
    case TYPE_STRING:
176
969k
    case TYPE_CHAR: {
177
969k
        return HashUtil::zlib_crc_hash(v, (uint32_t)len, seed);
178
968k
    }
179
180
135
    case TYPE_BOOLEAN:
181
3.11k
    case TYPE_TINYINT:
182
3.11k
        return HashUtil::zlib_crc_hash(v, 1, seed);
183
1.31k
    case TYPE_SMALLINT:
184
1.31k
        return HashUtil::zlib_crc_hash(v, 2, seed);
185
22.9M
    case TYPE_INT:
186
22.9M
        return HashUtil::zlib_crc_hash(v, 4, seed);
187
16.9M
    case TYPE_BIGINT:
188
16.9M
        return HashUtil::zlib_crc_hash(v, 8, seed);
189
28.1k
    case TYPE_LARGEINT:
190
28.1k
        return HashUtil::zlib_crc_hash(v, 16, seed);
191
0
    case TYPE_FLOAT:
192
0
        return HashUtil::zlib_crc_hash(v, 4, seed);
193
0
    case TYPE_DOUBLE:
194
0
        return HashUtil::zlib_crc_hash(v, 8, seed);
195
25
    case TYPE_DATE:
196
50
    case TYPE_DATETIME: {
197
50
        const auto* date_val = reinterpret_cast<const VecDateTimeValue*>(v);
198
50
        char buf[64];
199
50
        int date_len = date_val->to_buffer(buf);
200
50
        return HashUtil::zlib_crc_hash(buf, date_len, seed);
201
25
    }
202
203
1.77k
    case TYPE_DATEV2: {
204
1.77k
        return HashUtil::zlib_crc_hash(v, 4, seed);
205
25
    }
206
207
12.4k
    case TYPE_DATETIMEV2:
208
12.5k
    case TYPE_TIMESTAMP_NS: {
209
12.5k
        return HashUtil::zlib_crc_hash(v, 8, seed);
210
12.4k
    }
211
212
2.93k
    case TYPE_TIMESTAMPTZ: {
213
2.93k
        return HashUtil::zlib_crc_hash(v, 8, seed);
214
12.4k
    }
215
216
27
    case TYPE_DECIMALV2: {
217
27
        const auto* dec_val = reinterpret_cast<const DecimalV2Value*>(v);
218
27
        int64_t int_val = dec_val->int_value();
219
27
        int32_t frac_val = dec_val->frac_value();
220
27
        seed = HashUtil::zlib_crc_hash(&int_val, sizeof(int_val), seed);
221
27
        return HashUtil::zlib_crc_hash(&frac_val, sizeof(frac_val), seed);
222
12.4k
    }
223
156
    case TYPE_DECIMAL32:
224
156
        return HashUtil::zlib_crc_hash(v, 4, seed);
225
224
    case TYPE_DECIMAL64:
226
224
        return HashUtil::zlib_crc_hash(v, 8, seed);
227
428
    case TYPE_DECIMAL128I:
228
428
        return HashUtil::zlib_crc_hash(v, 16, seed);
229
4.37k
    case TYPE_DECIMAL256:
230
4.37k
        return HashUtil::zlib_crc_hash(v, 32, seed);
231
3
    case TYPE_IPV4:
232
3
        return HashUtil::zlib_crc_hash(v, 4, seed);
233
3
    case TYPE_IPV6:
234
125
    case TYPE_UUID:
235
125
        return HashUtil::zlib_crc_hash(v, 16, seed);
236
0
    default:
237
0
        DCHECK(false) << "invalid type: " << type;
238
0
        return 0;
239
40.9M
    }
240
40.9M
}
241
} // namespace doris