Coverage Report

Created: 2026-10-25 11:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/storage_layout.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 <bit>
21
#include <cmath>
22
#include <cstddef>
23
#include <cstdint>
24
#include <limits>
25
#include <string>
26
#include <type_traits>
27
28
#include "common/cast_set.h"
29
#include "common/logging.h"
30
#include "common/status.h"
31
#include "core/data_type/primitive_type.h"
32
#include "core/data_type/storage_field_type.h"
33
#include "core/decimal12.h"
34
#include "core/pod_array.h"
35
#include "core/string_ref.h"
36
#include "core/uint24.h"
37
#include "core/value/decimalv2_value.h"
38
#include "core/value/vdatetime_value.h"
39
#include "storage/field_type.h"
40
#include "storage/types.h"
41
#include "util/slice.h"
42
43
namespace doris {
44
45
class IColumn;
46
47
// How a compute-layer value becomes what a segment stores for FieldType FT:
48
// 1. Unchanged (BitCast): BOOL, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, UNSIGNED_INT,
49
//    UNSIGNED_BIGINT, DECIMAL32, DECIMAL64, DECIMAL128I, DECIMAL256, DATEV2,
50
//    DATETIMEV2, TIMESTAMP_NS, TIMESTAMPTZ, IPV4, IPV6, UUID.
51
// 2. Normalised (FloatingPoint): FLOAT and DOUBLE, every NaN as the quiet NaN.
52
// 3. Re-encoded (repack_from_column): the V1 DATE, DATETIME and DECIMAL layouts.
53
// 4. As bytes (Bytes): VARCHAR, STRING, JSONB, VARIANT; CHAR also zero padded to its
54
//    length.
55
// 5. Serialised: BITMAP, HLL, QUANTILE_STATE.
56
// 6. AGG_STATE: a string, a bitmap or a fixed-length object, whichever its aggregate
57
//    function serialises to; the column holding the states tells which.
58
// Compute-layer types: PrimitiveTypeTraits<PT>; storage-layer types: CppTypeTraits<FT>.
59
//
60
// Every layout converts a batch the same way: column_to_storage(column, row_pos, n, buffers)
61
// returns the stored cells of rows [row_pos, row_pos + n) back to back, n fixed-width values
62
// or n Slice descriptors. It returns the column's own bytes when they are stored unchanged
63
// and otherwise fills the StorageBuffers it is given, which the caller keeps until it has
64
// consumed the cells. Every row of the range is converted, NULL rows included: whatever a
65
// NULL row holds converts without harm, and no caller uses a NULL row's cell. CHAR padding is
66
// the one exception: it needs a range without NULL rows, see StorageLayout<CHAR>. to_storage
67
// retains a typed result for single-value key and predicate conversions.
68
template <FieldType FT>
69
struct StorageLayout;
70
71
// Where a batch conversion puts what it cannot borrow: converted fixed-width values and
72
// serialised payloads in `bytes`, the Slice descriptors of the byte types in `cells`.
73
struct StorageBuffers {
74
    PaddedPODArray<uint8_t> bytes;
75
    PaddedPODArray<Slice> cells;
76
};
77
78
// The FieldTypes stored fixed width, for callers that only know their FieldType at run
79
// time; the others are stored as bytes.
80
#define DORIS_APPLY_FOR_FIXED_WIDTH_STORAGE_LAYOUT_TYPES(M) \
81
168k
    M(OLAP_FIELD_TYPE_BOOL)                                 \
82
168k
    M(OLAP_FIELD_TYPE_TINYINT)                              \
83
60.9k
    M(OLAP_FIELD_TYPE_SMALLINT)                             \
84
891k
    M(OLAP_FIELD_TYPE_INT)                                  \
85
891k
    M(OLAP_FIELD_TYPE_BIGINT)                               \
86
598k
    M(OLAP_FIELD_TYPE_LARGEINT)                             \
87
22.1k
    M(OLAP_FIELD_TYPE_UNSIGNED_INT)                         \
88
0
    M(OLAP_FIELD_TYPE_UNSIGNED_BIGINT)                      \
89
12.3k
    M(OLAP_FIELD_TYPE_FLOAT)                                \
90
25.9k
    M(OLAP_FIELD_TYPE_DOUBLE)                               \
91
25.9k
    M(OLAP_FIELD_TYPE_DECIMAL)                              \
92
5.38k
    M(OLAP_FIELD_TYPE_DECIMAL32)                            \
93
18.9k
    M(OLAP_FIELD_TYPE_DECIMAL64)                            \
94
18.9k
    M(OLAP_FIELD_TYPE_DECIMAL128I)                          \
95
16.5k
    M(OLAP_FIELD_TYPE_DECIMAL256)                           \
96
1.49k
    M(OLAP_FIELD_TYPE_DATE)                                 \
97
835
    M(OLAP_FIELD_TYPE_DATETIME)                             \
98
43.0k
    M(OLAP_FIELD_TYPE_DATEV2)                               \
99
44.1k
    M(OLAP_FIELD_TYPE_DATETIMEV2)                           \
100
44.1k
    M(OLAP_FIELD_TYPE_TIMESTAMP_NS)                         \
101
7.75k
    M(OLAP_FIELD_TYPE_TIMESTAMPTZ)                          \
102
7.75k
    M(OLAP_FIELD_TYPE_IPV4)                                 \
103
736
    M(OLAP_FIELD_TYPE_IPV6)                                 \
104
26.3k
    M(OLAP_FIELD_TYPE_UUID)
105
106
namespace storage_layout_detail {
107
108
// A StorageValue is the PrimitiveValue's own bytes, so a run of the column is a run of
109
// stored values.
110
template <FieldType FT>
111
struct BitCast {
112
private:
113
    using StorageValue = typename CppTypeTraits<FT>::CppType;
114
    using PrimitiveValue =
115
            typename PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
116
    static_assert(sizeof(StorageValue) == sizeof(PrimitiveValue));
117
118
public:
119
28.3M
    static StorageValue to_storage(const PrimitiveValue& value) {
120
28.3M
        return std::bit_cast<StorageValue>(value);
121
28.3M
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE24EE10to_storageERKh
Line
Count
Source
119
21.7k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
21.7k
        return std::bit_cast<StorageValue>(value);
121
21.7k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE1EE10to_storageERKa
Line
Count
Source
119
263k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
263k
        return std::bit_cast<StorageValue>(value);
121
263k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE3EE10to_storageERKs
Line
Count
Source
119
212k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
212k
        return std::bit_cast<StorageValue>(value);
121
212k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE5EE10to_storageERKi
Line
Count
Source
119
18.6M
    static StorageValue to_storage(const PrimitiveValue& value) {
120
18.6M
        return std::bit_cast<StorageValue>(value);
121
18.6M
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE7EE10to_storageERKl
Line
Count
Source
119
7.60M
    static StorageValue to_storage(const PrimitiveValue& value) {
120
7.60M
        return std::bit_cast<StorageValue>(value);
121
7.60M
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE9EE10to_storageERKn
Line
Count
Source
119
43.6k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
43.6k
        return std::bit_cast<StorageValue>(value);
121
43.6k
    }
Unexecuted instantiation: _ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE6EE10to_storageERKj
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE8EE10to_storageERKm
Line
Count
Source
119
607
    static StorageValue to_storage(const PrimitiveValue& value) {
120
607
        return std::bit_cast<StorageValue>(value);
121
607
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE31EE10to_storageERKNS_7DecimalIiEE
Line
Count
Source
119
4.21k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
4.21k
        return std::bit_cast<StorageValue>(value);
121
4.21k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE32EE10to_storageERKNS_7DecimalIlEE
Line
Count
Source
119
3.58k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
3.58k
        return std::bit_cast<StorageValue>(value);
121
3.58k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE33EE10to_storageERKNS_12Decimal128V3E
Line
Count
Source
119
586k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
586k
        return std::bit_cast<StorageValue>(value);
121
586k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE37EE10to_storageERKNS_7DecimalIN4wide7integerILm256EiEEEE
Line
Count
Source
119
3.47k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
3.47k
        return std::bit_cast<StorageValue>(value);
121
3.47k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE28EE10to_storageERKNS_11DateV2ValueINS_15DateV2ValueTypeEEE
Line
Count
Source
119
297k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
297k
        return std::bit_cast<StorageValue>(value);
121
297k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE29EE10to_storageERKNS_11DateV2ValueINS_19DateTimeV2ValueTypeEEE
Line
Count
Source
119
601k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
601k
        return std::bit_cast<StorageValue>(value);
121
601k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE41EE10to_storageERKNS_16TimeStampNsValueE
Line
Count
Source
119
1.54k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
1.54k
        return std::bit_cast<StorageValue>(value);
121
1.54k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE40EE10to_storageERKNS_16TimestampTzValueE
Line
Count
Source
119
16.8k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
16.8k
        return std::bit_cast<StorageValue>(value);
121
16.8k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE38EE10to_storageERKj
Line
Count
Source
119
2.82k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
2.82k
        return std::bit_cast<StorageValue>(value);
121
2.82k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE39EE10to_storageERKo
Line
Count
Source
119
2.72k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
2.72k
        return std::bit_cast<StorageValue>(value);
121
2.72k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE42EE10to_storageERKo
Line
Count
Source
119
6.50k
    static StorageValue to_storage(const PrimitiveValue& value) {
120
6.50k
        return std::bit_cast<StorageValue>(value);
121
6.50k
    }
122
    // Always borrows the column's bytes.
123
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
124
                                            StorageBuffers& buffers);
125
};
126
127
// Every NaN is stored as the quiet NaN, so equal values have equal stored bytes
128
// and the bloom filter / dictionary / key encodings that hash or compare bytes
129
// treat all NaNs as one value.
130
template <FieldType FT>
131
struct FloatingPoint {
132
private:
133
    using StorageValue = typename CppTypeTraits<FT>::CppType;
134
    using PrimitiveValue =
135
            typename PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
136
    static_assert(std::is_floating_point_v<StorageValue>);
137
    static_assert(std::is_same_v<StorageValue, PrimitiveValue>);
138
139
public:
140
117k
    static StorageValue canonicalize_nan(StorageValue value) {
141
117k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
142
117k
    }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE10EE16canonicalize_nanEf
Line
Count
Source
140
52.0k
    static StorageValue canonicalize_nan(StorageValue value) {
141
52.0k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
142
52.0k
    }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE11EE16canonicalize_nanEd
Line
Count
Source
140
65.8k
    static StorageValue canonicalize_nan(StorageValue value) {
141
65.8k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
142
65.8k
    }
143
20.8k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE10EE10to_storageEf
Line
Count
Source
143
3.55k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE11EE10to_storageEd
Line
Count
Source
143
17.3k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
144
    // Borrows the column's bytes when [row_pos, row_pos + n) has no NaN, otherwise
145
    // converts the range into buffers.bytes. NaNs outside the range do not require a
146
    // copy; the source column is never modified.
147
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
148
                                            StorageBuffers& buffers);
149
};
150
151
// A string is stored as its own bytes, whatever their length: the cells are Slice
152
// descriptors of the column's payloads.
153
struct Bytes {
154
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
155
                                            StorageBuffers& buffers);
156
};
157
158
} // namespace storage_layout_detail
159
160
#define DORIS_STORAGE_LAYOUT_BIT_CAST(FT) \
161
    template <>                           \
162
    struct StorageLayout<FieldType::FT> : storage_layout_detail::BitCast<FieldType::FT> {};
163
164
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_BOOL)
165
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TINYINT)
166
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_SMALLINT)
167
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_INT)
168
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_BIGINT)
169
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_LARGEINT)
170
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UNSIGNED_INT)
171
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UNSIGNED_BIGINT)
172
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL32)
173
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL64)
174
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL128I)
175
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL256)
176
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DATEV2)
177
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DATETIMEV2)
178
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TIMESTAMP_NS)
179
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TIMESTAMPTZ)
180
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_IPV4)
181
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_IPV6)
182
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UUID)
183
#undef DORIS_STORAGE_LAYOUT_BIT_CAST
184
185
template <>
186
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_FLOAT>
187
        : storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_FLOAT> {};
188
189
template <>
190
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DOUBLE>
191
        : storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_DOUBLE> {};
192
193
// The batch conversions of the layouts above are instantiated once, in storage_layout.cpp.
194
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_BOOL>;
195
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_TINYINT>;
196
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_SMALLINT>;
197
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_INT>;
198
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_BIGINT>;
199
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_LARGEINT>;
200
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT>;
201
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT>;
202
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DECIMAL32>;
203
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DECIMAL64>;
204
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DECIMAL128I>;
205
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DECIMAL256>;
206
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DATEV2>;
207
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>;
208
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_TIMESTAMP_NS>;
209
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>;
210
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_IPV4>;
211
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_IPV6>;
212
extern template struct storage_layout_detail::BitCast<FieldType::OLAP_FIELD_TYPE_UUID>;
213
extern template struct storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_FLOAT>;
214
extern template struct storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_DOUBLE>;
215
216
// V1 DATE: three bytes of (year << 9) | (month << 5) | day.
217
template <>
218
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE> {
219
private:
220
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
221
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DATE>::CppType;
222
    static_assert(std::is_same_v<StorageValue, uint24_t>);
223
224
public:
225
1.54M
    static StorageValue to_storage(const PrimitiveValue& value) {
226
1.54M
        return StorageValue(cast_set<uint32_t>(value.to_olap_date()));
227
1.54M
    }
228
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
229
                                            StorageBuffers& buffers);
230
};
231
232
// V1 DATETIME: the decimal digits YYYYMMDDhhmmss packed into one integer.
233
template <>
234
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME> {
235
private:
236
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME>::CppType;
237
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DATETIME>::CppType;
238
    static_assert(std::is_same_v<StorageValue, int64_t>);
239
240
public:
241
1.42M
    static StorageValue to_storage(const PrimitiveValue& value) {
242
1.42M
        return static_cast<StorageValue>(value.to_olap_datetime());
243
1.42M
    }
244
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
245
                                            StorageBuffers& buffers);
246
};
247
248
// V1 DECIMAL: the integer and the nine-digit fraction stored side by side.
249
template <>
250
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL> {
251
private:
252
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL>::CppType;
253
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DECIMALV2>::CppType;
254
    static_assert(std::is_same_v<StorageValue, decimal12_t>);
255
256
public:
257
3.53k
    static StorageValue to_storage(const PrimitiveValue& value) {
258
3.53k
        return {value.int_value(), value.frac_value()};
259
3.53k
    }
260
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
261
                                            StorageBuffers& buffers);
262
};
263
264
template <>
265
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_VARCHAR> : storage_layout_detail::Bytes {};
266
267
template <>
268
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_STRING> : storage_layout_detail::Bytes {};
269
270
template <>
271
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_JSONB> : storage_layout_detail::Bytes {};
272
273
// A VARIANT root column reaches the writer as the JSONB of its rows.
274
template <>
275
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_VARIANT> : storage_layout_detail::Bytes {};
276
277
// CHAR(N) is stored zero padded to N bytes, while a block holds it unpadded: the writers
278
// pad the values they store or index with the length-taking column_to_storage. Padding
279
// copies a value into an N-byte slot, so it never reads a NULL row: a NULL row can hold a
280
// value longer than N, as load does not check NULL rows. The Bytes one stays for the SNII
281
// index, which is fed CHAR as it reads back.
282
template <>
283
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_CHAR> : storage_layout_detail::Bytes {
284
    using storage_layout_detail::Bytes::column_to_storage;
285
286
    // Pads every non-NULL row of the range into its own `length` zeroed bytes and points its
287
    // cell at them; a NULL row keeps an empty cell. null_map[i] is the NULL flag of row
288
    // row_pos + i, and null_map is nullptr when the range holds no NULL row.
289
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
290
                                            size_t length, const uint8_t* null_map,
291
                                            StorageBuffers& buffers);
292
293
4.23k
    static void append_padded(StringRef value, size_t length, std::string* out) {
294
        DCHECK_LE(value.size, length);
295
4.23k
        out->reserve(out->size() + length);
296
4.23k
        out->append(value.data, value.size);
297
4.23k
        out->append(length - value.size, '\0');
298
4.23k
    }
299
};
300
301
// The object types are stored serialised: every value of the batch into buffers.bytes,
302
// the cells pointing at them.
303
template <>
304
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_BITMAP> {
305
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
306
                                            StorageBuffers& buffers);
307
};
308
309
template <>
310
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_HLL> {
311
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
312
                                            StorageBuffers& buffers);
313
};
314
315
template <>
316
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE> {
317
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
318
                                            StorageBuffers& buffers);
319
};
320
321
// The fixed-length objects an AGG_STATE column holds when its aggregate function serialises
322
// to them, each borrowed through a Slice descriptor. String and bitmap states are stored
323
// through the VARCHAR and BITMAP layouts, which the column writer is given when it is created.
324
template <>
325
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_AGG_STATE> {
326
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
327
                                            StorageBuffers& buffers);
328
};
329
330
// The batch conversion of a FieldType known only at run time: the column_to_storage of
331
// StorageLayout<type>, for the column writer and the index feeds. CHAR is not accepted:
332
// whether its values are padded is the caller's choice, made through StorageLayout<CHAR>.
333
const uint8_t* column_to_storage(FieldType type, const IColumn& column, size_t row_pos, size_t n,
334
                                 StorageBuffers& buffers);
335
336
// The admission rule a writer applies to the rows of a column before they are stored: a
337
// STRING or JSONB value must fit string_type_length_soft_limit_bytes, and a JSONB value
338
// must be a well-formed JSONB document. The rows `null_map` marks NULL are not checked.
339
Status admit_storage_rows(FieldType type, const IColumn& column, size_t row_pos, size_t n,
340
                          const uint8_t* null_map);
341
342
} // namespace doris