Coverage Report

Created: 2026-10-21 21:40

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_fwd.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
42
namespace doris {
43
44
class IColumn;
45
46
// How a compute-layer value becomes what a segment stores for FieldType FT:
47
// 1. Unchanged (BitCast): BOOL, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, UNSIGNED_INT,
48
//    UNSIGNED_BIGINT, DECIMAL32, DECIMAL64, DECIMAL128I, DECIMAL256, DATEV2,
49
//    DATETIMEV2, TIMESTAMP_NS, TIMESTAMPTZ, IPV4, IPV6, UUID.
50
// 2. Normalised (FloatingPoint): FLOAT and DOUBLE, every NaN as the quiet NaN.
51
// 3. Re-encoded (repack_from_column): the V1 DATE, DATETIME and DECIMAL layouts.
52
// 4. As bytes (Bytes): VARCHAR, STRING, JSONB, VARIANT; CHAR also zero padded to its
53
//    length.
54
// 5. Serialised: BITMAP, HLL, QUANTILE_STATE.
55
// 6. AGG_STATE: a string, a bitmap or a fixed-length object, whichever its aggregate
56
//    function serialises to.
57
// Compute-layer types: PrimitiveTypeTraits<PT>; storage-layer types: CppTypeTraits<FT>.
58
//
59
// Batch conversions return stored cells as bytes: fixed-width values or Slice descriptors.
60
// Source bytes are borrowed when no conversion is needed; converted bytes use caller-owned
61
// buffers. storage_at returns one Slice in the supplied descriptor, whose payload is borrowed
62
// or held in tmp_buffer. Consumers must finish before either buffer is reused.
63
// to_storage retains a typed result for single-value key and predicate conversions.
64
template <FieldType FT>
65
struct StorageLayout;
66
67
// The FieldTypes stored fixed width, for callers that only know their FieldType at run
68
// time; the others are stored as bytes.
69
#define DORIS_APPLY_FOR_FIXED_WIDTH_STORAGE_LAYOUT_TYPES(M) \
70
6.60k
    M(OLAP_FIELD_TYPE_BOOL)                                 \
71
6.60k
    M(OLAP_FIELD_TYPE_TINYINT)                              \
72
5.86k
    M(OLAP_FIELD_TYPE_SMALLINT)                             \
73
10.2k
    M(OLAP_FIELD_TYPE_INT)                                  \
74
10.2k
    M(OLAP_FIELD_TYPE_BIGINT)                               \
75
2.26k
    M(OLAP_FIELD_TYPE_LARGEINT)                             \
76
1.15k
    M(OLAP_FIELD_TYPE_UNSIGNED_INT)                         \
77
607
    M(OLAP_FIELD_TYPE_UNSIGNED_BIGINT)                      \
78
1.12k
    M(OLAP_FIELD_TYPE_FLOAT)                                \
79
1.12k
    M(OLAP_FIELD_TYPE_DOUBLE)                               \
80
1.14k
    M(OLAP_FIELD_TYPE_DECIMAL)                              \
81
1.21k
    M(OLAP_FIELD_TYPE_DECIMAL32)                            \
82
1.21k
    M(OLAP_FIELD_TYPE_DECIMAL64)                            \
83
1.14k
    M(OLAP_FIELD_TYPE_DECIMAL128I)                          \
84
1.14k
    M(OLAP_FIELD_TYPE_DECIMAL256)                           \
85
1.59k
    M(OLAP_FIELD_TYPE_DATE)                                 \
86
1.59k
    M(OLAP_FIELD_TYPE_DATETIME)                             \
87
1.22k
    M(OLAP_FIELD_TYPE_DATEV2)                               \
88
1.22k
    M(OLAP_FIELD_TYPE_DATETIMEV2)                           \
89
1.14k
    M(OLAP_FIELD_TYPE_TIMESTAMP_NS)                         \
90
1.14k
    M(OLAP_FIELD_TYPE_TIMESTAMPTZ)                          \
91
1.21k
    M(OLAP_FIELD_TYPE_IPV4)                                 \
92
1.21k
    M(OLAP_FIELD_TYPE_IPV6)                                 \
93
1.14k
    M(OLAP_FIELD_TYPE_UUID)
94
95
namespace storage_layout_detail {
96
97
// A StorageValue is the PrimitiveValue's own bytes, so a run of the column is a run of
98
// stored values.
99
template <FieldType FT>
100
struct BitCast {
101
private:
102
    using StorageValue = typename CppTypeTraits<FT>::CppType;
103
    using PrimitiveValue =
104
            typename PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
105
    static_assert(sizeof(StorageValue) == sizeof(PrimitiveValue));
106
107
public:
108
    // Every value can be borrowed without inspection or conversion.
109
    static constexpr bool is_direct = true;
110
111
491k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
491k
        return std::bit_cast<StorageValue>(value);
113
491k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE7EE10to_storageERKl
Line
Count
Source
111
2.69k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.69k
        return std::bit_cast<StorageValue>(value);
113
2.69k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE24EE10to_storageERKh
Line
Count
Source
111
8.02k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
8.02k
        return std::bit_cast<StorageValue>(value);
113
8.02k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE31EE10to_storageERKNS_7DecimalIiEE
Line
Count
Source
111
2.41k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.41k
        return std::bit_cast<StorageValue>(value);
113
2.41k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE32EE10to_storageERKNS_7DecimalIlEE
Line
Count
Source
111
2.34k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.34k
        return std::bit_cast<StorageValue>(value);
113
2.34k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE33EE10to_storageERKNS_12Decimal128V3E
Line
Count
Source
111
2.33k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.33k
        return std::bit_cast<StorageValue>(value);
113
2.33k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE37EE10to_storageERKNS_7DecimalIN4wide7integerILm256EiEEEE
Line
Count
Source
111
2.33k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.33k
        return std::bit_cast<StorageValue>(value);
113
2.33k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE28EE10to_storageERKNS_11DateV2ValueINS_15DateV2ValueTypeEEE
Line
Count
Source
111
2.41k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.41k
        return std::bit_cast<StorageValue>(value);
113
2.41k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE29EE10to_storageERKNS_11DateV2ValueINS_19DateTimeV2ValueTypeEEE
Line
Count
Source
111
2.35k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.35k
        return std::bit_cast<StorageValue>(value);
113
2.35k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE40EE10to_storageERKNS_16TimestampTzValueE
Line
Count
Source
111
2.37k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.37k
        return std::bit_cast<StorageValue>(value);
113
2.37k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE1EE10to_storageERKa
Line
Count
Source
111
5.68k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
5.68k
        return std::bit_cast<StorageValue>(value);
113
5.68k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE3EE10to_storageERKs
Line
Count
Source
111
3.57k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
3.57k
        return std::bit_cast<StorageValue>(value);
113
3.57k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE5EE10to_storageERKi
Line
Count
Source
111
445k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
445k
        return std::bit_cast<StorageValue>(value);
113
445k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE9EE10to_storageERKn
Line
Count
Source
111
2.34k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.34k
        return std::bit_cast<StorageValue>(value);
113
2.34k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE38EE10to_storageERKj
Line
Count
Source
111
2.39k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.39k
        return std::bit_cast<StorageValue>(value);
113
2.39k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE39EE10to_storageERKo
Line
Count
Source
111
2.33k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
2.33k
        return std::bit_cast<StorageValue>(value);
113
2.33k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE42EE10to_storageERKo
Line
Count
Source
111
1.02k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
1.02k
        return std::bit_cast<StorageValue>(value);
113
1.02k
    }
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE41EE10to_storageERKNS_16TimeStampNsValueE
Line
Count
Source
111
1.07k
    static StorageValue to_storage(const PrimitiveValue& value) {
112
1.07k
        return std::bit_cast<StorageValue>(value);
113
1.07k
    }
Unexecuted instantiation: _ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE6EE10to_storageERKj
_ZN5doris21storage_layout_detail7BitCastILNS_9FieldTypeE8EE10to_storageERKm
Line
Count
Source
111
607
    static StorageValue to_storage(const PrimitiveValue& value) {
112
607
        return std::bit_cast<StorageValue>(value);
113
607
    }
114
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
115
                                            PaddedPODArray<char>& buffer,
116
                                            const uint8_t* null_map = nullptr);
117
};
118
119
// Every NaN is stored as the quiet NaN, so equal values have equal stored bytes
120
// and the bloom filter / dictionary / key encodings that hash or compare bytes
121
// treat all NaNs as one value.
122
template <FieldType FT>
123
struct FloatingPoint {
124
private:
125
    using StorageValue = typename CppTypeTraits<FT>::CppType;
126
    using PrimitiveValue =
127
            typename PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
128
    static_assert(std::is_floating_point_v<StorageValue>);
129
    static_assert(std::is_same_v<StorageValue, PrimitiveValue>);
130
131
public:
132
    static constexpr bool is_direct = false;
133
134
113k
    static StorageValue canonicalize_nan(StorageValue value) {
135
113k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
136
113k
    }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE10EE16canonicalize_nanEf
Line
Count
Source
134
50.9k
    static StorageValue canonicalize_nan(StorageValue value) {
135
50.9k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
136
50.9k
    }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE11EE16canonicalize_nanEd
Line
Count
Source
134
62.4k
    static StorageValue canonicalize_nan(StorageValue value) {
135
62.4k
        return std::isnan(value) ? std::numeric_limits<StorageValue>::quiet_NaN() : value;
136
62.4k
    }
137
16.2k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE10EE10to_storageEf
Line
Count
Source
137
2.38k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
_ZN5doris21storage_layout_detail13FloatingPointILNS_9FieldTypeE11EE10to_storageEd
Line
Count
Source
137
13.9k
    static StorageValue to_storage(PrimitiveValue value) { return canonicalize_nan(value); }
138
    // The returned bytes belong to the source column when [row_pos, row_pos + n) has
139
    // no NaN, otherwise to buffer until it is reused. NaNs outside the range do not
140
    // require a copy; the source column is never modified.
141
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
142
                                            PaddedPODArray<char>& buffer,
143
                                            const uint8_t* null_map = nullptr);
144
};
145
146
// A string is stored as its own bytes, whatever their length.
147
struct Bytes {
148
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
149
                                            Slice* cells, const uint8_t* null_map = nullptr);
150
    static const uint8_t* storage_at(const IColumn& column, size_t row,
151
                                     PaddedPODArray<char>& tmp_buffer, Slice* cell);
152
};
153
154
} // namespace storage_layout_detail
155
156
#define DORIS_STORAGE_LAYOUT_BIT_CAST(FT)                                                   \
157
    template <>                                                                             \
158
    struct StorageLayout<FieldType::FT> : storage_layout_detail::BitCast<FieldType::FT> {}; \
159
    extern template struct storage_layout_detail::BitCast<FieldType::FT>;
160
161
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_BOOL)
162
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TINYINT)
163
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_SMALLINT)
164
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_INT)
165
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_BIGINT)
166
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_LARGEINT)
167
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UNSIGNED_INT)
168
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UNSIGNED_BIGINT)
169
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL32)
170
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL64)
171
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL128I)
172
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DECIMAL256)
173
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DATEV2)
174
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_DATETIMEV2)
175
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TIMESTAMP_NS)
176
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_TIMESTAMPTZ)
177
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_IPV4)
178
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_IPV6)
179
DORIS_STORAGE_LAYOUT_BIT_CAST(OLAP_FIELD_TYPE_UUID)
180
#undef DORIS_STORAGE_LAYOUT_BIT_CAST
181
182
template <>
183
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_FLOAT>
184
        : storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_FLOAT> {};
185
186
template <>
187
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DOUBLE>
188
        : storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_DOUBLE> {};
189
190
extern template struct storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_FLOAT>;
191
extern template struct storage_layout_detail::FloatingPoint<FieldType::OLAP_FIELD_TYPE_DOUBLE>;
192
193
// V1 DATE: three bytes of (year << 9) | (month << 5) | day.
194
template <>
195
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE> {
196
private:
197
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
198
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DATE>::CppType;
199
    static_assert(std::is_same_v<StorageValue, uint24_t>);
200
201
public:
202
    static constexpr bool is_direct = false;
203
204
118k
    static StorageValue to_storage(const PrimitiveValue& value) {
205
118k
        return StorageValue(cast_set<uint32_t>(value.to_olap_date()));
206
118k
    }
207
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
208
                                            PaddedPODArray<char>& buffer,
209
                                            const uint8_t* null_map = nullptr);
210
};
211
212
// V1 DATETIME: the decimal digits YYYYMMDDhhmmss packed into one integer.
213
template <>
214
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME> {
215
private:
216
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME>::CppType;
217
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DATETIME>::CppType;
218
    static_assert(std::is_same_v<StorageValue, int64_t>);
219
220
public:
221
    static constexpr bool is_direct = false;
222
223
3.04k
    static StorageValue to_storage(const PrimitiveValue& value) {
224
3.04k
        return static_cast<StorageValue>(value.to_olap_datetime());
225
3.04k
    }
226
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
227
                                            PaddedPODArray<char>& buffer,
228
                                            const uint8_t* null_map = nullptr);
229
};
230
231
// V1 DECIMAL: the integer and the nine-digit fraction stored side by side.
232
template <>
233
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL> {
234
private:
235
    using StorageValue = typename CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL>::CppType;
236
    using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DECIMALV2>::CppType;
237
    static_assert(std::is_same_v<StorageValue, decimal12_t>);
238
239
public:
240
    static constexpr bool is_direct = false;
241
242
2.94k
    static StorageValue to_storage(const PrimitiveValue& value) {
243
2.94k
        return {value.int_value(), value.frac_value()};
244
2.94k
    }
245
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
246
                                            PaddedPODArray<char>& buffer,
247
                                            const uint8_t* null_map = nullptr);
248
};
249
250
template <>
251
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_VARCHAR> : storage_layout_detail::Bytes {};
252
253
template <>
254
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_STRING> : storage_layout_detail::Bytes {};
255
256
template <>
257
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_JSONB> : storage_layout_detail::Bytes {};
258
259
// A VARIANT root column reaches the writer as the JSONB of its rows.
260
template <>
261
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_VARIANT> : storage_layout_detail::Bytes {};
262
263
// CHAR(N) is stored zero padded to N bytes, while a block holds it unpadded: the column
264
// writer pads the columns it stores, and storage_at reads a row of the padded column.
265
template <>
266
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_CHAR> : storage_layout_detail::Bytes {
267
    static bool is_padded(const IColumn& column, size_t length);
268
269
    // Pad selected non-NULL CHAR values into bytes and point the descriptors at them.
270
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
271
                                            size_t length, PaddedPODArray<char>& buffer,
272
                                            Slice* cells, const uint8_t* null_map = nullptr);
273
274
    // Writes only [row_pos, row_pos + n) to rows [0, n) of the reusable output column.
275
    // NULL payloads are not read; their output bytes are zero padded as well.
276
    static void pad_column(const IColumn& column, size_t row_pos, size_t n, size_t length,
277
                           ColumnString& out);
278
279
    // Input and output have the same nullability. Copy the matching null-map range so
280
    // both the item writer and array index can read the compact buffer from row 0.
281
    static void pad_column_with_nulls(const IColumn& column, size_t row_pos, size_t n,
282
                                      size_t length, IColumn& out);
283
284
1.31k
    static void append_padded(StringRef value, size_t length, std::string* out) {
285
        DCHECK_LE(value.size, length);
286
1.31k
        out->reserve(out->size() + length);
287
1.31k
        out->append(value.data, value.size);
288
1.31k
        out->append(length - value.size, '\0');
289
1.31k
    }
290
};
291
292
// The object types are stored serialised.
293
template <>
294
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_BITMAP> {
295
    static const uint8_t* storage_at(const IColumn& column, size_t row,
296
                                     PaddedPODArray<char>& tmp_buffer, Slice* cell);
297
};
298
299
template <>
300
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_HLL> {
301
    static const uint8_t* storage_at(const IColumn& column, size_t row,
302
                                     PaddedPODArray<char>& tmp_buffer, Slice* cell);
303
};
304
305
template <>
306
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE> {
307
    static const uint8_t* storage_at(const IColumn& column, size_t row,
308
                                     PaddedPODArray<char>& tmp_buffer, Slice* cell);
309
};
310
311
// An AGG_STATE column holds strings, bitmaps or fixed-length objects, whichever its
312
// aggregate function serialises to, so storage_at_of picks the storage_at once per batch.
313
template <>
314
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_AGG_STATE> {
315
    using StorageAt = const uint8_t* (*)(const IColumn& column, size_t row,
316
                                         PaddedPODArray<char>& tmp_buffer, Slice* cell);
317
    static StorageAt storage_at_of(const IColumn& column);
318
    static bool needs_serialization(const IColumn& column);
319
    // Borrow serialized string/fixed-object payloads through a batch of Slice descriptors.
320
    static const uint8_t* column_to_storage(const IColumn& column, size_t row_pos, size_t n,
321
                                            PaddedPODArray<Slice>& buffer);
322
323
private:
324
    static const uint8_t* fixed_length_object_at(const IColumn& column, size_t row,
325
                                                 PaddedPODArray<char>& tmp_buffer, Slice* cell);
326
};
327
328
// The admission rule a writer applies to the rows of a column before they are stored: a
329
// STRING or JSONB value must fit string_type_length_soft_limit_bytes, and a JSONB value
330
// must be a well-formed JSONB document. The rows `null_map` marks NULL are not checked.
331
Status admit_storage_rows(FieldType type, const IColumn& column, size_t row_pos, size_t n,
332
                          const uint8_t* null_map);
333
334
} // namespace doris