This is an automated email from the ASF dual-hosted git repository.
csun5285 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 3d2d9aac541 [refactor](be) Read stored values through StorageLayout
(#69609)
3d2d9aac541 is described below
commit 3d2d9aac54148056529c13ef4b9fbdbcb65fab77
Author: Chenyang Sun <[email protected]>
AuthorDate: Tue Oct 27 18:30:46 2026 +0800
[refactor](be) Read stored values through StorageLayout (#69609)
Read stored values through StorageLayout
---
be/src/core/column/column.h | 6 -
be/src/core/column/column_decimal.cpp | 19 --
be/src/core/column/column_decimal.h | 2 -
be/src/core/column/column_nullable.h | 5 -
be/src/core/column/column_vector.h | 40 ----
be/src/core/data_type/primitive_type.h | 43 -----
.../data_type_serde/data_type_decimal_serde.cpp | 1 +
be/src/core/field.h | 23 ---
.../aggregate/aggregate_function_window_funnel.h | 1 -
be/src/storage/field_type.h | 2 +-
.../bloom_filter/bloom_filter_index_writer.cpp | 2 +-
.../index/inverted/clucene/inverted_index_writer.h | 2 +-
be/src/storage/index/zone_map/zone_map_index.cpp | 13 +-
be/src/storage/index/zone_map/zone_map_index.h | 7 +-
be/src/storage/key_coder.h | 33 ++--
be/src/storage/segment/binary_dict_page.cpp | 2 +-
be/src/storage/segment/bitshuffle_page.h | 7 +-
be/src/storage/segment/column_reader.cpp | 49 ++++-
be/src/storage/segment/encoding_info.cpp | 20 +-
be/src/storage/segment/encoding_info.h | 6 +-
be/src/storage/segment/plain_page.h | 7 +-
be/src/storage/storage_layout.cpp | 42 ++++-
be/src/storage/storage_layout.h | 54 ++++--
be/src/storage/types.h | 208 ++++++++++-----------
be/test/core/column/column_array_test.cpp | 9 -
be/test/core/column/column_decimal_test.cpp | 6 -
be/test/core/column/column_vector_test.cpp | 24 ---
be/test/core/column/common_column_test.h | 49 -----
.../writer/iceberg/partition_transformers_test.cpp | 16 +-
be/test/storage/index/date_bloom_filter_test.cpp | 24 +--
be/test/storage/index/index_builder_test.cpp | 2 +-
.../inverted/snii/bkd/bkd_differential_test.cpp | 4 +-
.../index/inverted/snii/bkd/bkd_property_test.cpp | 10 +-
.../inverted/snii/snii_bkd_adapter_types_test.cpp | 4 +-
be/test/storage/key_coder_test.cpp | 35 ++--
be/test/storage/olap_type_test.cpp | 37 ++--
be/test/storage/row_cursor_test.cpp | 14 +-
be/test/storage/segment/bitshuffle_page_test.cpp | 82 ++++++++
.../bloom_filter_index_reader_writer_test.cpp | 2 +-
.../storage/segment/inverted_index_reader_test.cpp | 21 +--
.../storage/segment/page_builder_column_test.cpp | 12 +-
be/test/storage/segment/page_format_test.cpp | 124 ++++++++----
be/test/storage/segment/plain_page_test.cpp | 68 +++++++
be/test/storage/storage_layout_test.cpp | 116 +++++++++++-
.../storage_layout_test_util.h} | 30 ++-
45 files changed, 736 insertions(+), 547 deletions(-)
diff --git a/be/src/core/column/column.h b/be/src/core/column/column.h
index bde5b4786c1..ad2b6cba3e1 100644
--- a/be/src/core/column/column.h
+++ b/be/src/core/column/column.h
@@ -239,12 +239,6 @@ public:
"Method insert_data is not supported for " +
get_name());
}
- virtual void insert_many_fix_len_data(const char* pos, size_t num) {
- throw doris::Exception(
- ErrorCode::NOT_IMPLEMENTED_ERROR,
- "Method insert_many_fix_len_data is not supported for " +
get_name());
- }
-
// todo(zeno) Use dict_args temp object to cover all arguments
virtual void insert_many_dict_data(const int32_t* data_array, size_t
start_index,
const StringRef* dict, size_t data_num,
diff --git a/be/src/core/column/column_decimal.cpp
b/be/src/core/column/column_decimal.cpp
index 314bccd5d54..cbc21186c46 100644
--- a/be/src/core/column/column_decimal.cpp
+++ b/be/src/core/column/column_decimal.cpp
@@ -30,7 +30,6 @@
#include "core/column/columns_common.h"
#include "core/data_type/data_type.h"
#include "core/data_type/data_type_decimal.h"
-#include "core/decimal12.h"
#include "core/value/decimalv2_value.h"
#include "exec/common/int_exp.h"
#include "exec/common/sip_hash.h"
@@ -390,24 +389,6 @@ void ColumnDecimal<T>::insert_data(const char* src, size_t
/*length*/) {
data.emplace_back(tmp);
}
-template <PrimitiveType T>
-void ColumnDecimal<T>::insert_many_fix_len_data(const char* data_ptr, size_t
num) {
- size_t old_size = data.size();
- data.resize(old_size + num);
-
- if constexpr (T == TYPE_DECIMALV2) {
- DecimalV2Value* target = (DecimalV2Value*)(data.data() + old_size);
- for (int i = 0; i < num; i++) {
- const char* cur_ptr = data_ptr + sizeof(decimal12_t) * i;
- auto int_value = unaligned_load<int64_t>(cur_ptr);
- auto frac_value = unaligned_load<int32_t>(cur_ptr +
sizeof(int64_t));
- target[i].from_olap_decimal(int_value, frac_value);
- }
- } else {
- memcpy(data.data() + old_size, data_ptr, num * sizeof(value_type));
- }
-}
-
template <PrimitiveType T>
void ColumnDecimal<T>::insert_many_from(const IColumn& src, size_t position,
size_t length) {
auto old_size = data.size();
diff --git a/be/src/core/column/column_decimal.h
b/be/src/core/column/column_decimal.h
index 8cd7be991a7..23ae05b4a85 100644
--- a/be/src/core/column/column_decimal.h
+++ b/be/src/core/column/column_decimal.h
@@ -128,8 +128,6 @@ public:
data.data() + origin_size, indices_begin, indices_end);
}
- void insert_many_fix_len_data(const char* data_ptr, size_t num) override;
-
void insert_many_raw_data(const char* pos, size_t num) override {
DCHECK(pos);
size_t old_size = data.size();
diff --git a/be/src/core/column/column_nullable.h
b/be/src/core/column/column_nullable.h
index c90f72d4400..382ce7c4fc4 100644
--- a/be/src/core/column/column_nullable.h
+++ b/be/src/core/column/column_nullable.h
@@ -161,11 +161,6 @@ public:
_null_map->insert_from(src_concrete.get_null_map_column(), n);
}
- void insert_many_fix_len_data(const char* pos, size_t num) override {
- push_false_to_nullmap(num);
- get_nested_column().insert_many_fix_len_data(pos, num);
- }
-
void insert_many_raw_data(const char* pos, size_t num) override {
DCHECK(pos);
push_false_to_nullmap(num);
diff --git a/be/src/core/column/column_vector.h
b/be/src/core/column/column_vector.h
index 5f27d18566b..b6d79ae9d26 100644
--- a/be/src/core/column/column_vector.h
+++ b/be/src/core/column/column_vector.h
@@ -47,7 +47,6 @@
#include "core/pod_array_fwd.h"
#include "core/string_ref.h"
#include "core/types.h"
-#include "core/uint24.h"
#include "core/value/timestamp_ns_value.h"
#include "core/value/vdatetime_value.h"
#include "util/unaligned.h"
@@ -133,45 +132,6 @@ public:
}
}
- void insert_date_column(const char* data_ptr, size_t num) {
- data.reserve(data.size() + num);
- constexpr size_t input_value_size = sizeof(uint24_t);
-
- for (int i = 0; i < num; i++) {
- uint24_t val = 0;
- memcpy((char*)(&val), data_ptr, input_value_size);
- data_ptr += input_value_size;
-
- VecDateTimeValue date;
- date.set_olap_date(val);
- data.push_back_without_reserve(date);
- }
- }
-
- void insert_datetime_column(const char* data_ptr, size_t num) {
- data.reserve(data.size() + num);
- size_t value_size = sizeof(uint64_t);
- for (int i = 0; i < num; i++) {
- const char* cur_ptr = data_ptr + value_size * i;
- auto value = unaligned_load<uint64_t>(cur_ptr);
- VecDateTimeValue datetime =
VecDateTimeValue::create_from_olap_datetime(value);
- this->insert_data(reinterpret_cast<char*>(&datetime), 0);
- }
- }
-
- /*
- use by date, datetime, basic type
- */
- void insert_many_fix_len_data(const char* data_ptr, size_t num) override {
- if (T == TYPE_DATE) {
- insert_date_column(data_ptr, num);
- } else if (T == TYPE_DATETIME) {
- insert_datetime_column(data_ptr, num);
- } else {
- insert_many_raw_data(data_ptr, num);
- }
- }
-
void insert_many_raw_data(const char* data_ptr, size_t num) override {
DCHECK(data_ptr);
auto old_size = data.size();
diff --git a/be/src/core/data_type/primitive_type.h
b/be/src/core/data_type/primitive_type.h
index 71591884ce5..41506fe5953 100644
--- a/be/src/core/data_type/primitive_type.h
+++ b/be/src/core/data_type/primitive_type.h
@@ -27,10 +27,8 @@
#include "common/cast_set.h"
#include "core/data_type/define_primitive_type.h"
-#include "core/decimal12.h"
#include "core/string_view.h"
#include "core/types.h"
-#include "core/uint24.h"
#include "core/value/timestamptz_value.h"
#include "core/value/vdatetime_value.h"
#include "exec/common/template_helpers.hpp"
@@ -284,113 +282,96 @@ struct PrimitiveTypeTraits;
/**
* CppType: Doris type in execution engine
- * StorageFieldType: Doris type in storage engine
* DataType: DataType which is mapping to this PrimitiveType
* ColumnType: ColumnType which is mapping to this PrimitiveType
*/
template <>
struct PrimitiveTypeTraits<TYPE_BOOLEAN> {
using CppType = UInt8;
- using StorageFieldType = CppType;
using DataType = DataTypeBool;
using ColumnType = ColumnUInt8;
};
template <>
struct PrimitiveTypeTraits<TYPE_TINYINT> {
using CppType = int8_t;
- using StorageFieldType = CppType;
using DataType = DataTypeInt8;
using ColumnType = ColumnInt8;
};
template <>
struct PrimitiveTypeTraits<TYPE_SMALLINT> {
using CppType = int16_t;
- using StorageFieldType = CppType;
using DataType = DataTypeInt16;
using ColumnType = ColumnInt16;
};
template <>
struct PrimitiveTypeTraits<TYPE_INT> {
using CppType = int32_t;
- using StorageFieldType = CppType;
using DataType = DataTypeInt32;
using ColumnType = ColumnInt32;
};
template <>
struct PrimitiveTypeTraits<TYPE_BIGINT> {
using CppType = int64_t;
- using StorageFieldType = CppType;
using DataType = DataTypeInt64;
using ColumnType = ColumnInt64;
};
template <>
struct PrimitiveTypeTraits<TYPE_LARGEINT> {
using CppType = __int128_t;
- using StorageFieldType = CppType;
using DataType = DataTypeInt128;
using ColumnType = ColumnInt128;
};
template <>
struct PrimitiveTypeTraits<TYPE_NULL> {
using CppType = Null;
- using StorageFieldType = CppType;
using DataType = DataTypeNothing;
using ColumnType = IColumnDummy;
};
template <>
struct PrimitiveTypeTraits<TYPE_FLOAT> {
using CppType = float;
- using StorageFieldType = CppType;
using DataType = DataTypeFloat32;
using ColumnType = ColumnFloat32;
};
template <>
struct PrimitiveTypeTraits<TYPE_DOUBLE> {
using CppType = double;
- using StorageFieldType = CppType;
using DataType = DataTypeFloat64;
using ColumnType = ColumnFloat64;
};
template <>
struct PrimitiveTypeTraits<TYPE_TIMEV2> {
using CppType = Float64;
- using StorageFieldType = CppType;
using DataType = DataTypeTimeV2;
using ColumnType = ColumnTimeV2;
};
template <>
struct PrimitiveTypeTraits<TYPE_DATE> {
using CppType = doris::VecDateTimeValue;
- /// Different with compute layer, the DateV1 was stored as uint24_t(3
bytes).
- using StorageFieldType = uint24_t;
using DataType = DataTypeDate;
using ColumnType = ColumnDate;
};
template <>
struct PrimitiveTypeTraits<TYPE_DATETIME> {
using CppType = doris::VecDateTimeValue;
- using StorageFieldType = uint64_t;
using DataType = DataTypeDateTime;
using ColumnType = ColumnDateTime;
};
template <>
struct PrimitiveTypeTraits<TYPE_DATETIMEV2> {
using CppType = DateV2Value<DateTimeV2ValueType>;
- using StorageFieldType = uint64_t;
using DataType = DataTypeDateTimeV2;
using ColumnType = ColumnDateTimeV2;
};
template <>
struct PrimitiveTypeTraits<TYPE_TIMESTAMP_NS> {
using CppType = TimeStampNsValue;
- using StorageFieldType = int64_t;
using DataType = DataTypeTimeStampNs;
using ColumnType = ColumnTimeStampNs;
};
template <>
struct PrimitiveTypeTraits<TYPE_DATEV2> {
using CppType = DateV2Value<DateV2ValueType>;
- using StorageFieldType = uint32_t;
using DataType = DataTypeDateV2;
using ColumnType = ColumnDateV2;
};
@@ -398,7 +379,6 @@ struct PrimitiveTypeTraits<TYPE_DATEV2> {
template <>
struct PrimitiveTypeTraits<TYPE_TIMESTAMPTZ> {
using CppType = TimestampTzValue;
- using StorageFieldType = uint64_t;
using DataType = DataTypeTimeStampTz;
using ColumnType = ColumnTimeStampTz;
};
@@ -406,155 +386,132 @@ struct PrimitiveTypeTraits<TYPE_TIMESTAMPTZ> {
template <>
struct PrimitiveTypeTraits<TYPE_DECIMALV2> {
using CppType = DecimalV2Value;
- /// Different with compute layer, the DecimalV1 was stored as
decimal12_t(12 bytes).
- using StorageFieldType = decimal12_t;
using DataType = DataTypeDecimalV2;
using ColumnType = ColumnDecimal128V2;
};
template <>
struct PrimitiveTypeTraits<TYPE_DECIMAL32> {
using CppType = Decimal32;
- using StorageFieldType = Int32;
using DataType = DataTypeDecimal32;
using ColumnType = ColumnDecimal32;
};
template <>
struct PrimitiveTypeTraits<TYPE_DECIMAL64> {
using CppType = Decimal64;
- using StorageFieldType = Int64;
using DataType = DataTypeDecimal64;
using ColumnType = ColumnDecimal64;
};
template <>
struct PrimitiveTypeTraits<TYPE_DECIMAL128I> {
using CppType = Decimal128V3;
- using StorageFieldType = Int128;
using DataType = DataTypeDecimal128;
using ColumnType = ColumnDecimal128V3;
};
template <>
struct PrimitiveTypeTraits<TYPE_DECIMAL256> {
using CppType = Decimal256;
- using StorageFieldType = wide::Int256;
using DataType = DataTypeDecimal256;
using ColumnType = ColumnDecimal256;
};
template <>
struct PrimitiveTypeTraits<TYPE_IPV4> {
using CppType = IPv4;
- using StorageFieldType = CppType;
using DataType = DataTypeIPv4;
using ColumnType = ColumnIPv4;
};
template <>
struct PrimitiveTypeTraits<TYPE_IPV6> {
using CppType = IPv6;
- using StorageFieldType = CppType;
using DataType = DataTypeIPv6;
using ColumnType = ColumnIPv6;
};
template <>
struct PrimitiveTypeTraits<TYPE_UUID> {
using CppType = UUIDValueType;
- using StorageFieldType = CppType;
using DataType = DataTypeUUID;
using ColumnType = ColumnUUID;
};
template <>
struct PrimitiveTypeTraits<TYPE_CHAR> {
using CppType = String;
- using StorageFieldType = CppType;
using DataType = DataTypeString;
using ColumnType = ColumnString;
};
template <>
struct PrimitiveTypeTraits<TYPE_VARCHAR> {
using CppType = String;
- using StorageFieldType = CppType;
using DataType = DataTypeString;
using ColumnType = ColumnString;
};
template <>
struct PrimitiveTypeTraits<TYPE_STRING> {
using CppType = String;
- using StorageFieldType = CppType;
using DataType = DataTypeString;
using ColumnType = ColumnString;
};
template <>
struct PrimitiveTypeTraits<TYPE_VARBINARY> {
using CppType = doris::StringView;
- using StorageFieldType = CppType;
using DataType = DataTypeVarbinary;
using ColumnType = ColumnVarbinary;
};
template <>
struct PrimitiveTypeTraits<TYPE_HLL> {
using CppType = HyperLogLog;
- using StorageFieldType = CppType;
using DataType = DataTypeHLL;
using ColumnType = ColumnHLL;
};
template <>
struct PrimitiveTypeTraits<TYPE_JSONB> {
using CppType = JsonbField;
- using StorageFieldType = CppType;
using DataType = DataTypeJsonb;
using ColumnType = ColumnString;
};
template <>
struct PrimitiveTypeTraits<TYPE_ARRAY> {
using CppType = Array;
- using StorageFieldType = CppType;
using DataType = DataTypeArray;
using ColumnType = ColumnArray;
};
template <>
struct PrimitiveTypeTraits<TYPE_MAP> {
using CppType = Map;
- using StorageFieldType = CppType;
using DataType = DataTypeMap;
using ColumnType = ColumnMap;
};
template <>
struct PrimitiveTypeTraits<TYPE_STRUCT> {
using CppType = Struct;
- using StorageFieldType = CppType;
using DataType = DataTypeStruct;
using ColumnType = ColumnStruct;
};
template <>
struct PrimitiveTypeTraits<TYPE_VARIANT> {
using CppType = VariantField;
- using StorageFieldType = CppType;
using DataType = DataTypeVariant;
using ColumnType = ColumnVariantV2;
};
template <>
struct PrimitiveTypeTraits<TYPE_BITMAP> {
using CppType = BitmapValue;
- using StorageFieldType = CppType;
using DataType = DataTypeBitMap;
using ColumnType = ColumnBitmap;
};
template <>
struct PrimitiveTypeTraits<TYPE_QUANTILE_STATE> {
using CppType = QuantileState;
- using StorageFieldType = CppType;
using DataType = DataTypeQuantileState;
using ColumnType = ColumnQuantileState;
};
template <>
struct PrimitiveTypeTraits<TYPE_UINT32> {
using CppType = UInt32;
- using StorageFieldType = CppType;
using DataType = DataTypeUInt32;
using ColumnType = ColumnOffset32;
};
template <>
struct PrimitiveTypeTraits<TYPE_UINT64> {
using CppType = UInt64;
- using StorageFieldType = CppType;
using DataType = DataTypeUInt64;
using ColumnType = ColumnOffset64;
};
diff --git a/be/src/core/data_type_serde/data_type_decimal_serde.cpp
b/be/src/core/data_type_serde/data_type_decimal_serde.cpp
index bb136460743..7c8e92a5788 100644
--- a/be/src/core/data_type_serde/data_type_decimal_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_decimal_serde.cpp
@@ -39,6 +39,7 @@
#include "core/data_type_serde/decoded_column_view.h"
#include "core/data_type_serde/orc_serde_utils.h"
#include "core/data_type_serde/parquet_decode_source.h"
+#include "core/decimal12.h"
#include "core/types.h"
#include "exec/common/arithmetic_overflow.h"
#include "exec/common/endian.h"
diff --git a/be/src/core/field.h b/be/src/core/field.h
index 155278fa337..60b391bc211 100644
--- a/be/src/core/field.h
+++ b/be/src/core/field.h
@@ -204,29 +204,6 @@ public:
return f;
}
- template <PrimitiveType PType, typename ValType = std::conditional_t<
- doris::is_string_type(PType),
StringRef,
- typename
PrimitiveTypeTraits<PType>::StorageFieldType>>
- static Field create_field_from_olap_value(const ValType& data) {
- auto f = Field(PType);
- typename PrimitiveTypeTraits<PType>::CppType cpp_value;
- if constexpr (is_string_type(PType)) {
- cpp_value = String(data.data, data.size);
- } else if constexpr (is_date_or_datetime(PType)) {
- if constexpr (PType == TYPE_DATE) {
- cpp_value.from_olap_date(data);
- } else {
- cpp_value.from_olap_datetime(data);
- }
- } else if constexpr (is_decimalv2(PType)) {
- cpp_value = DecimalV2Value(data.integer, data.fraction);
- } else {
- cpp_value = typename PrimitiveTypeTraits<PType>::CppType(data);
- }
- f.template create_concrete<PType>(std::move(cpp_value));
- return f;
- }
-
/** Despite the presence of a template constructor, this constructor is
still needed,
* since, in its absence, the compiler will still generate the default
constructor.
*/
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel.h
b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
index 7069cf9ca00..d7686fb5e9e 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel.h
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
@@ -102,7 +102,6 @@ struct DataValue {
template <PrimitiveType T>
struct WindowFunnelState {
static constexpr PrimitiveType PType = T;
- using NativeType = typename PrimitiveTypeTraits<T>::StorageFieldType;
using DateValueType = typename PrimitiveTypeTraits<T>::CppType;
int event_count = 0;
int64_t window;
diff --git a/be/src/storage/field_type.h b/be/src/storage/field_type.h
index f27df867645..965dd5a835c 100644
--- a/be/src/storage/field_type.h
+++ b/be/src/storage/field_type.h
@@ -20,7 +20,7 @@
namespace doris {
// Storage-engine cell types, used by TabletColumn / KeyCoder and the
-// data_type traits chain. When adding a new value, also extend CppTypeTraits,
+// data_type traits chain. When adding a new value, also extend
StorageTypeTraits,
// FieldTypeTraits and the field_type_size() switch in storage/types.h. Decide
how it maps to
// PrimitiveType and explicitly define its behavior in
primitive_type_to_storage_field_type() and
// storage_field_type_to_primitive_type(), either by providing a mapping or by
throwing.
diff --git a/be/src/storage/index/bloom_filter/bloom_filter_index_writer.cpp
b/be/src/storage/index/bloom_filter/bloom_filter_index_writer.cpp
index 06da761a099..b1f7aa42565 100644
--- a/be/src/storage/index/bloom_filter/bloom_filter_index_writer.cpp
+++ b/be/src/storage/index/bloom_filter/bloom_filter_index_writer.cpp
@@ -63,7 +63,7 @@ struct BloomFilterTraits<int128_t> {
template <FieldType field_type>
class BloomFilterIndexWriterImpl : public BloomFilterIndexWriter {
public:
- using CppType = typename CppTypeTraits<field_type>::CppType;
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
using ValueDict = typename BloomFilterTraits<CppType>::ValueDict;
explicit BloomFilterIndexWriterImpl(const BloomFilterOptions& bf_options)
diff --git a/be/src/storage/index/inverted/clucene/inverted_index_writer.h
b/be/src/storage/index/inverted/clucene/inverted_index_writer.h
index ef6d21aa8a5..51ff4546d44 100644
--- a/be/src/storage/index/inverted/clucene/inverted_index_writer.h
+++ b/be/src/storage/index/inverted/clucene/inverted_index_writer.h
@@ -43,7 +43,7 @@ using namespace doris::segment_v2::inverted_index;
template <FieldType field_type>
class InvertedIndexColumnWriter : public IndexColumnWriter {
public:
- using CppType = typename CppTypeTraits<field_type>::CppType;
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
InvertedIndexColumnWriter(const std::string& field_name, IndexFileWriter*
index_file_writer,
const TabletIndex* index_meta, const bool
single_field = true);
diff --git a/be/src/storage/index/zone_map/zone_map_index.cpp
b/be/src/storage/index/zone_map/zone_map_index.cpp
index d2b086cc51b..5e96d91a7c2 100644
--- a/be/src/storage/index/zone_map/zone_map_index.cpp
+++ b/be/src/storage/index/zone_map/zone_map_index.cpp
@@ -36,6 +36,7 @@
#include "storage/index/indexed_column_writer.h"
#include "storage/olap_common.h"
#include "storage/segment/encoding_info.h"
+#include "storage/storage_layout.h"
#include "storage/tablet/tablet_schema.h"
#include "storage/types.h"
#include "storage/utils.h"
@@ -205,8 +206,16 @@ void
TypedZoneMapIndexWriter<Type>::_materialize_page_minmax() {
if (!_page_zone_map.has_not_null) {
return;
}
- _page_zone_map.min_value =
doris::Field::create_field_from_olap_value<Type>(_page_min);
- _page_zone_map.max_value =
doris::Field::create_field_from_olap_value<Type>(_page_max);
+ if constexpr (is_string_type(Type)) {
+ _page_zone_map.min_value =
+ Field::create_field<Type>(String(_page_min.data,
_page_min.size));
+ _page_zone_map.max_value =
+ Field::create_field<Type>(String(_page_max.data,
_page_max.size));
+ } else {
+ using Layout =
StorageLayout<primitive_type_to_storage_field_type(Type)>;
+ _page_zone_map.min_value =
Field::create_field<Type>(Layout::to_primitive(_page_min));
+ _page_zone_map.max_value =
Field::create_field<Type>(Layout::to_primitive(_page_max));
+ }
}
template <PrimitiveType Type>
diff --git a/be/src/storage/index/zone_map/zone_map_index.h
b/be/src/storage/index/zone_map/zone_map_index.h
index 7360fb9f797..9b44badbcae 100644
--- a/be/src/storage/index/zone_map/zone_map_index.h
+++ b/be/src/storage/index/zone_map/zone_map_index.h
@@ -29,10 +29,12 @@
#include "common/status.h"
#include "core/data_type/data_type.h"
#include "core/data_type/define_primitive_type.h"
+#include "core/data_type/storage_field_type.h"
#include "core/string_ref.h"
#include "io/fs/file_reader_writer_fwd.h"
#include "storage/metadata_adder.h"
#include "storage/tablet/tablet_schema.h"
+#include "storage/types.h"
#include "util/once.h"
namespace doris {
@@ -118,8 +120,9 @@ public:
template <PrimitiveType Type>
class TypedZoneMapIndexWriter final : public ZoneMapIndexWriter {
public:
- using ValType = std::conditional_t<is_string_type(Type), StringRef,
- typename
PrimitiveTypeTraits<Type>::StorageFieldType>;
+ using ValType = std::conditional_t<
+ is_string_type(Type), StringRef,
+ typename
StorageTypeTraits<primitive_type_to_storage_field_type(Type)>::StorageType>;
explicit TypedZoneMapIndexWriter(DataTypePtr&& data_type);
void add_values(const uint8_t* values, size_t count) override;
diff --git a/be/src/storage/key_coder.h b/be/src/storage/key_coder.h
index 8076e940174..c9d5bbeb8c5 100644
--- a/be/src/storage/key_coder.h
+++ b/be/src/storage/key_coder.h
@@ -84,13 +84,14 @@ template <FieldType field_type, typename Enable = void>
class KeyCoderTraits {};
template <FieldType field_type>
-class KeyCoderTraits<field_type,
- typename std::enable_if<
- IsIntegral<typename
CppTypeTraits<field_type>::CppType>::value ||
- IsDecimalNumber<typename
CppTypeTraits<field_type>::CppType>>::type> {
+class KeyCoderTraits<
+ field_type,
+ typename std::enable_if<
+ IsIntegral<typename
StorageTypeTraits<field_type>::StorageType>::value ||
+ IsDecimalNumber<typename
StorageTypeTraits<field_type>::StorageType>>::type> {
public:
- using CppType = typename CppTypeTraits<field_type>::CppType;
- using UnsignedCppType = typename
CppTypeTraits<field_type>::UnsignedCppType;
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
+ using UnsignedCppType = typename
StorageTypeTraits<field_type>::UnsignedStorageType;
static void full_encode_ascending(const void* value, std::string* buf) {
UnsignedCppType unsigned_val;
@@ -133,9 +134,9 @@ public:
template <>
class KeyCoderTraits<FieldType::OLAP_FIELD_TYPE_DATE> {
public:
- using CppType = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
+ using CppType = typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::StorageType;
using UnsignedCppType =
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::UnsignedCppType;
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::UnsignedStorageType;
public:
static void full_encode_ascending(const void* value, std::string* buf) {
@@ -167,9 +168,9 @@ public:
template <>
class KeyCoderTraits<FieldType::OLAP_FIELD_TYPE_DATEV2> {
public:
- using CppType = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::CppType;
+ using CppType = typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::StorageType;
using UnsignedCppType =
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::UnsignedCppType;
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::UnsignedStorageType;
public:
static void full_encode_ascending(const void* value, std::string* buf) {
@@ -202,9 +203,9 @@ public:
template <>
class KeyCoderTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2> {
public:
- using CppType = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::CppType;
+ using CppType = typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::StorageType;
using UnsignedCppType =
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::UnsignedCppType;
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::UnsignedStorageType;
public:
static void full_encode_ascending(const void* value, std::string* buf) {
@@ -237,9 +238,9 @@ public:
template <>
class KeyCoderTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ> {
public:
- using CppType = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::CppType;
+ using CppType = typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::StorageType;
using UnsignedCppType =
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::UnsignedCppType;
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::UnsignedStorageType;
public:
static void full_encode_ascending(const void* value, std::string* buf) {
@@ -361,8 +362,8 @@ public:
template <FieldType field_type>
class KeyCoderTraitsForFloat {
public:
- using CppType = typename CppTypeTraits<field_type>::CppType;
- using UnsignedCppType = typename
CppTypeTraits<field_type>::UnsignedCppType;
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
+ using UnsignedCppType = typename
StorageTypeTraits<field_type>::UnsignedStorageType;
static UnsignedCppType encode_float(CppType value) {
return sortable_float_bits(float_to_int_bits(value));
diff --git a/be/src/storage/segment/binary_dict_page.cpp
b/be/src/storage/segment/binary_dict_page.cpp
index fb85020bb15..97f1bb4a657 100644
--- a/be/src/storage/segment/binary_dict_page.cpp
+++ b/be/src/storage/segment/binary_dict_page.cpp
@@ -288,7 +288,7 @@ Status BinaryDictPageDecoder::next_batch(size_t* n,
MutableColumnPtr& dst) {
// without copying actual char data. This allows length() to work.
// ColumnDictI32 does not implement insert_offsets_from_lengths, so
convert
// it to a predicate column (ColumnString) first. This is a no-op for
- // non-dictionary columns and for ColumnNullable it converts the
nested column.
+ // non-dictionary columns; a Nullable never reaches a page decoder.
dst = dst->convert_to_predicate_column_if_dictionary();
const auto* data_array = reinterpret_cast<const
int32_t*>(_bit_shuffle_ptr->get_data(0));
size_t start_index = _bit_shuffle_ptr->_cur_index;
diff --git a/be/src/storage/segment/bitshuffle_page.h
b/be/src/storage/segment/bitshuffle_page.h
index 0d58fdb17d5..b480de9426a 100644
--- a/be/src/storage/segment/bitshuffle_page.h
+++ b/be/src/storage/segment/bitshuffle_page.h
@@ -38,6 +38,7 @@
#include "storage/segment/options.h"
#include "storage/segment/page_builder.h"
#include "storage/segment/page_decoder.h"
+#include "storage/storage_layout.h"
#include "storage/types.h"
#include "util/alignment.h"
#include "util/coding.h"
@@ -393,7 +394,8 @@ public:
size_t max_fetch = std::min(*n, _num_elements - _cur_index);
- dst->insert_many_fix_len_data(get_data(_cur_index), max_fetch);
+ StorageLayout<Type>::storage_to_column(
+ reinterpret_cast<const uint8_t*>(get_data(_cur_index)),
max_fetch, *dst);
*n = max_fetch;
if constexpr (forward_index) {
_cur_index += max_fetch;
@@ -425,7 +427,8 @@ public:
}
if (LIKELY(read_count > 0)) {
- dst->insert_many_fix_len_data((char*)_buffer.data(), read_count);
+ StorageLayout<Type>::storage_to_column(reinterpret_cast<const
uint8_t*>(_buffer.data()),
+ read_count, *dst);
}
*n = read_count;
diff --git a/be/src/storage/segment/column_reader.cpp
b/be/src/storage/segment/column_reader.cpp
index 30d123a4d8b..ea660a07187 100644
--- a/be/src/storage/segment/column_reader.cpp
+++ b/be/src/storage/segment/column_reader.cpp
@@ -2924,6 +2924,34 @@ Status
FileColumnIterator::next_batch_of_zone_map(size_t* n, MutableColumnPtr& d
return _reader->next_batch_of_zone_map(n, dst);
}
+namespace {
+
+// Runs `decode`, a page decoder call that appends values to the column it is
given. The decoders
+// append to the column of the type, as ScalarColumnWriter::append peels the
Nullable off before
+// the values reach a page, so a Nullable dst lends them its nested column and
the rows they
+// append are marked not NULL here. A dictionary page decoder may replace the
column it appends to
+// (a ColumnDictI32 becomes a ColumnString when a page falls back to plain
encoding), and the
+// replacement goes back into dst.
+template <typename Decode>
+Status decode_values(MutableColumnPtr& dst, const Decode& decode) {
+ if (!is_column_nullable(*dst)) {
+ return decode(dst);
+ }
+ auto& nullable = static_cast<ColumnNullable&>(*dst);
+ MutableColumnPtr nested = nullable.get_nested_column_ptr();
+ const IColumn* const lent = nested.get();
+ const size_t rows = lent->size();
+ Status st = decode(nested);
+ nullable.push_false_to_nullmap(nested->size() - rows);
+ if (nested.get() != lent) {
+ ColumnPtr replacement = std::move(nested);
+ nullable.change_nested_column(replacement);
+ }
+ return st;
+}
+
+} // namespace
+
Status FileColumnIterator::next_batch(size_t* n, MutableColumnPtr& dst, bool*
has_null) {
if (!need_to_read()) {
DLOG(INFO) << "File column iterator column " << _column_name << " skip
reading.";
@@ -3004,7 +3032,9 @@ Status FileColumnIterator::next_batch(size_t* n,
MutableColumnPtr& dst, bool* ha
// we use num_rows only for CHECK
size_t num_rows = this_run;
if (!is_null) {
- RETURN_IF_ERROR(_page.data_decoder->next_batch(&num_rows,
dst));
+ RETURN_IF_ERROR(decode_values(dst, [&](MutableColumnPtr&
values) {
+ return _page.data_decoder->next_batch(&num_rows,
values);
+ }));
DCHECK_EQ(this_run, num_rows);
} else {
*has_null = true;
@@ -3021,7 +3051,9 @@ Status FileColumnIterator::next_batch(size_t* n,
MutableColumnPtr& dst, bool* ha
_current_ordinal += this_run;
}
} else {
- RETURN_IF_ERROR(_page.data_decoder->next_batch(&nrows_to_read,
dst));
+ RETURN_IF_ERROR(decode_values(dst, [&](MutableColumnPtr& values) {
+ return _page.data_decoder->next_batch(&nrows_to_read, values);
+ }));
DCHECK_EQ(nrows_to_read, nrows_in_page);
_page.offset_in_page += nrows_to_read;
@@ -3168,8 +3200,11 @@ Status FileColumnIterator::read_by_rowids(const rowid_t*
rowids, const size_t co
// so we need use `page_start_off_in_decoder` to
calculate the actual offset in `data_decoder`
size_t page_start_off_in_decoder =
_page.first_ordinal + _page.offset_in_page -
origin_index;
- RETURN_IF_ERROR(_page.data_decoder->read_by_rowids(
- &rowids[offset], page_start_off_in_decoder,
&read_count, dst));
+ RETURN_IF_ERROR(decode_values(dst,
[&](MutableColumnPtr& values) {
+ return
_page.data_decoder->read_by_rowids(&rowids[offset],
+
page_start_off_in_decoder,
+
&read_count, values);
+ }));
DCHECK_EQ(read_count, this_read_count);
}
}
@@ -3188,8 +3223,10 @@ Status FileColumnIterator::read_by_rowids(const rowid_t*
rowids, const size_t co
total_read_count += nrows_to_read;
remaining -= nrows_to_read;
} else {
- RETURN_IF_ERROR(_page.data_decoder->read_by_rowids(
- &rowids[total_read_count], _page.first_ordinal,
&nrows_to_read, dst));
+ RETURN_IF_ERROR(decode_values(dst, [&](MutableColumnPtr& values) {
+ return _page.data_decoder->read_by_rowids(
+ &rowids[total_read_count], _page.first_ordinal,
&nrows_to_read, values);
+ }));
total_read_count += nrows_to_read;
remaining -= nrows_to_read;
}
diff --git a/be/src/storage/segment/encoding_info.cpp
b/be/src/storage/segment/encoding_info.cpp
index 7490a8fe4cf..dc8655c248e 100644
--- a/be/src/storage/segment/encoding_info.cpp
+++ b/be/src/storage/segment/encoding_info.cpp
@@ -151,8 +151,9 @@ struct TypeEncodingTraits<type, DICT_ENCODING, Slice> {
};
template <>
-struct TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATE, FOR_ENCODING,
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType> {
+struct TypeEncodingTraits<
+ FieldType::OLAP_FIELD_TYPE_DATE, FOR_ENCODING,
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::StorageType> {
static Status create_page_builder(const PageBuilderOptions& opts,
PageBuilder** builder) {
return
FrameOfReferencePageBuilder<FieldType::OLAP_FIELD_TYPE_DATE>::create(builder,
opts);
}
@@ -164,8 +165,9 @@ struct TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATE,
FOR_ENCODING,
};
template <>
-struct TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATEV2, FOR_ENCODING,
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::CppType> {
+struct TypeEncodingTraits<
+ FieldType::OLAP_FIELD_TYPE_DATEV2, FOR_ENCODING,
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2>::StorageType> {
static Status create_page_builder(const PageBuilderOptions& opts,
PageBuilder** builder) {
return
FrameOfReferencePageBuilder<FieldType::OLAP_FIELD_TYPE_DATEV2>::create(builder,
opts);
@@ -178,8 +180,9 @@ struct
TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATEV2, FOR_ENCODING,
};
template <>
-struct TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2, FOR_ENCODING,
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::CppType> {
+struct TypeEncodingTraits<
+ FieldType::OLAP_FIELD_TYPE_DATETIMEV2, FOR_ENCODING,
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::StorageType> {
static Status create_page_builder(const PageBuilderOptions& opts,
PageBuilder** builder) {
return
FrameOfReferencePageBuilder<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>::create(builder,
opts);
@@ -193,8 +196,9 @@ struct
TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2, FOR_ENCODING,
};
template <>
-struct TypeEncodingTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ, FOR_ENCODING,
- typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::CppType> {
+struct TypeEncodingTraits<
+ FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ, FOR_ENCODING,
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::StorageType> {
static Status create_page_builder(const PageBuilderOptions& opts,
PageBuilder** builder) {
return
FrameOfReferencePageBuilder<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>::create(builder,
opts);
diff --git a/be/src/storage/segment/encoding_info.h
b/be/src/storage/segment/encoding_info.h
index dfbf7b1d7cf..c5ce7eed27a 100644
--- a/be/src/storage/segment/encoding_info.h
+++ b/be/src/storage/segment/encoding_info.h
@@ -27,7 +27,7 @@
#include "common/status.h"
#include "storage/cache/page_cache.h"
#include "storage/segment/options.h"
-#include "storage/types.h" // CppTypeTraits, used by the EncodingTraits base
below
+#include "storage/types.h" // StorageTypeTraits, used by the EncodingTraits
base below
#include "util/slice.h"
namespace doris {
@@ -172,8 +172,8 @@ struct TypeEncodingTraits {};
template <FieldType field_type, EncodingTypePB encoding_type>
struct EncodingTraits : TypeEncodingTraits<field_type, encoding_type,
- typename
CppTypeTraits<field_type>::CppType> {
- using CppType = typename CppTypeTraits<field_type>::CppType;
+ typename
StorageTypeTraits<field_type>::StorageType> {
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
static const FieldType type = field_type;
static const EncodingTypePB encoding = encoding_type;
};
diff --git a/be/src/storage/segment/plain_page.h
b/be/src/storage/segment/plain_page.h
index cfc5e428dc8..76b72a999bc 100644
--- a/be/src/storage/segment/plain_page.h
+++ b/be/src/storage/segment/plain_page.h
@@ -22,6 +22,7 @@
#include "storage/segment/options.h"
#include "storage/segment/page_builder.h"
#include "storage/segment/page_decoder.h"
+#include "storage/storage_layout.h"
#include "storage/types.h"
#include "util/coding.h"
#include "util/faststring.h"
@@ -191,7 +192,8 @@ public:
size_t max_fetch = std::min(*n, static_cast<size_t>(_num_elems -
_cur_idx));
const void* src_data = &_data[PLAIN_PAGE_HEADER_SIZE + _cur_idx *
SIZE_OF_TYPE];
- dst->insert_many_fix_len_data((const char*)src_data, max_fetch);
+ StorageLayout<Type>::storage_to_column(static_cast<const
uint8_t*>(src_data), max_fetch,
+ *dst);
*n = max_fetch;
_cur_idx += max_fetch;
@@ -220,7 +222,8 @@ public:
}
if (LIKELY(read_count > 0)) {
- dst->insert_many_fix_len_data((char*)_buffer.data(), read_count);
+ StorageLayout<Type>::storage_to_column(reinterpret_cast<const
uint8_t*>(_buffer.data()),
+ read_count, *dst);
}
*n = read_count;
diff --git a/be/src/storage/storage_layout.cpp
b/be/src/storage/storage_layout.cpp
index 2e10e040475..6bd8107d436 100644
--- a/be/src/storage/storage_layout.cpp
+++ b/be/src/storage/storage_layout.cpp
@@ -47,9 +47,14 @@ const uint8_t* BitCast<FT>::column_to_storage(const IColumn&
column, size_t row_
row_pos);
}
+template <FieldType FT>
+void BitCast<FT>::storage_to_column(const uint8_t* values, size_t n, IColumn&
dst) {
+ dst.insert_many_raw_data(reinterpret_cast<const char*>(values), n);
+}
+
template <FieldType FT>
void repack_from_column(const IColumn& column, size_t row_pos, size_t n,
uint8_t* dst) {
- using StorageValue = typename CppTypeTraits<FT>::CppType;
+ using StorageValue = typename StorageTypeTraits<FT>::StorageType;
using Column =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::ColumnType;
const auto& data = assert_cast<const Column&>(column).get_data();
@@ -59,6 +64,21 @@ void repack_from_column(const IColumn& column, size_t
row_pos, size_t n, uint8_t
}
}
+// Appends n stored values of a repacked layout, each turned back into its
PrimitiveValue.
+template <FieldType FT>
+void repack_to_column(const uint8_t* values, size_t n, IColumn& dst) {
+ using StorageValue = typename StorageTypeTraits<FT>::StorageType;
+ using Column =
+ typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::ColumnType;
+ auto& data = assert_cast<Column&>(dst).get_data();
+ data.reserve(data.size() + n);
+ for (size_t i = 0; i < n; ++i) {
+ StorageValue value;
+ memcpy(&value, values + i * sizeof(StorageValue),
sizeof(StorageValue));
+ data.push_back_without_reserve(StorageLayout<FT>::to_primitive(value));
+ }
+}
+
template <FieldType FT>
const uint8_t* FloatingPoint<FT>::column_to_storage(const IColumn& column,
size_t row_pos, size_t n,
StorageBuffers& buffers) {
@@ -81,6 +101,11 @@ const uint8_t* FloatingPoint<FT>::column_to_storage(const
IColumn& column, size_
return bytes.data();
}
+template <FieldType FT>
+void FloatingPoint<FT>::storage_to_column(const uint8_t* values, size_t n,
IColumn& dst) {
+ dst.insert_many_raw_data(reinterpret_cast<const char*>(values), n);
+}
+
const uint8_t* Bytes::column_to_storage(const IColumn& column, size_t row_pos,
size_t n,
StorageBuffers& buffers) {
const auto& strings = assert_cast<const ColumnString&>(column);
@@ -167,6 +192,21 @@ const uint8_t*
StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL>::column_to_stor
return buffers.bytes.data();
}
+void StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>::storage_to_column(const
uint8_t* values,
+ size_t
n, IColumn& dst) {
+
storage_layout_detail::repack_to_column<FieldType::OLAP_FIELD_TYPE_DATE>(values,
n, dst);
+}
+
+void
StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME>::storage_to_column(const
uint8_t* values,
+
size_t n, IColumn& dst) {
+
storage_layout_detail::repack_to_column<FieldType::OLAP_FIELD_TYPE_DATETIME>(values,
n, dst);
+}
+
+void
StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL>::storage_to_column(const
uint8_t* values,
+
size_t n, IColumn& dst) {
+
storage_layout_detail::repack_to_column<FieldType::OLAP_FIELD_TYPE_DECIMAL>(values,
n, dst);
+}
+
const uint8_t*
StorageLayout<FieldType::OLAP_FIELD_TYPE_CHAR>::column_to_storage(
const IColumn& column, size_t row_pos, size_t n, size_t length, const
uint8_t* null_map,
StorageBuffers& buffers) {
diff --git a/be/src/storage/storage_layout.h b/be/src/storage/storage_layout.h
index 17cdc6d404f..2831f3cf16a 100644
--- a/be/src/storage/storage_layout.h
+++ b/be/src/storage/storage_layout.h
@@ -55,7 +55,7 @@ class IColumn;
// 5. Serialised: BITMAP, HLL, QUANTILE_STATE.
// 6. AGG_STATE: a string, a bitmap or a fixed-length object, whichever its
aggregate
// function serialises to; the column holding the states tells which.
-// Compute-layer types: PrimitiveTypeTraits<PT>; storage-layer types:
CppTypeTraits<FT>.
+// Compute-layer types: PrimitiveTypeTraits<PT>; storage-layer types:
StorageTypeTraits<FT>.
//
// Every layout converts a batch the same way: column_to_storage(column,
row_pos, n, buffers)
// returns the stored cells of rows [row_pos, row_pos + n) back to back, n
fixed-width values
@@ -65,6 +65,12 @@ class IColumn;
// NULL row holds converts without harm, and no caller uses a NULL row's cell.
CHAR padding is
// the one exception: it needs a range without NULL rows, see
StorageLayout<CHAR>. to_storage
// retains a typed result for single-value key and predicate conversions.
+//
+// The fixed-width layouts also read back. to_primitive is the inverse of
to_storage for one
+// value, and storage_to_column(values, n, dst) appends the n stored values at
`values`, which
+// need not be aligned, to `dst`, the column of the PrimitiveType:
FileColumnIterator peels a
+// Nullable off first, as ScalarColumnWriter::append does. The page decoders
read through it,
+// and the zone map turns its stored bounds back with to_primitive.
template <FieldType FT>
struct StorageLayout;
@@ -109,19 +115,22 @@ namespace storage_layout_detail {
// stored values.
template <FieldType FT>
struct BitCast {
-private:
- using StorageValue = typename CppTypeTraits<FT>::CppType;
+ using StorageValue = typename StorageTypeTraits<FT>::StorageType;
using PrimitiveValue =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
static_assert(sizeof(StorageValue) == sizeof(PrimitiveValue));
-public:
static StorageValue to_storage(const PrimitiveValue& value) {
return std::bit_cast<StorageValue>(value);
}
+ static PrimitiveValue to_primitive(const StorageValue& value) {
+ return std::bit_cast<PrimitiveValue>(value);
+ }
// Always borrows the column's bytes.
static const uint8_t* column_to_storage(const IColumn& column, size_t
row_pos, size_t n,
StorageBuffers& buffers);
+ // One copy: the stored values are the column's values.
+ static void storage_to_column(const uint8_t* values, size_t n, IColumn&
dst);
};
// Every NaN is stored as the quiet NaN, so equal values have equal stored
bytes
@@ -129,23 +138,25 @@ public:
// treat all NaNs as one value.
template <FieldType FT>
struct FloatingPoint {
-private:
- using StorageValue = typename CppTypeTraits<FT>::CppType;
+ using StorageValue = typename StorageTypeTraits<FT>::StorageType;
using PrimitiveValue =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::CppType;
static_assert(std::is_floating_point_v<StorageValue>);
static_assert(std::is_same_v<StorageValue, PrimitiveValue>);
-public:
static StorageValue canonicalize_nan(StorageValue value) {
return std::isnan(value) ?
std::numeric_limits<StorageValue>::quiet_NaN() : value;
}
static StorageValue to_storage(PrimitiveValue value) { return
canonicalize_nan(value); }
+ // A stored value is read back as it is: only writing canonicalises.
+ static PrimitiveValue to_primitive(StorageValue value) { return value; }
// Borrows the column's bytes when [row_pos, row_pos + n) has no NaN,
otherwise
// converts the range into buffers.bytes. NaNs outside the range do not
require a
// copy; the source column is never modified.
static const uint8_t* column_to_storage(const IColumn& column, size_t
row_pos, size_t n,
StorageBuffers& buffers);
+ // One copy: the stored values are the column's values.
+ static void storage_to_column(const uint8_t* values, size_t n, IColumn&
dst);
};
// A string is stored as its own bytes, whatever their length: the cells are
Slice
@@ -216,49 +227,60 @@ extern template struct
storage_layout_detail::FloatingPoint<FieldType::OLAP_FIEL
// V1 DATE: three bytes of (year << 9) | (month << 5) | day.
template <>
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE> {
-private:
- using StorageValue = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
+ using StorageValue = typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::StorageType;
using PrimitiveValue = typename PrimitiveTypeTraits<TYPE_DATE>::CppType;
static_assert(std::is_same_v<StorageValue, uint24_t>);
-public:
static StorageValue to_storage(const PrimitiveValue& value) {
return StorageValue(cast_set<uint32_t>(value.to_olap_date()));
}
+ // The fields are taken as stored: a date was checked when it was written.
+ static PrimitiveValue to_primitive(const StorageValue& value) {
+ PrimitiveValue primitive;
+ primitive.set_olap_date(value);
+ return primitive;
+ }
static const uint8_t* column_to_storage(const IColumn& column, size_t
row_pos, size_t n,
StorageBuffers& buffers);
+ static void storage_to_column(const uint8_t* values, size_t n, IColumn&
dst);
};
// V1 DATETIME: the decimal digits YYYYMMDDhhmmss packed into one integer.
template <>
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME> {
-private:
- using StorageValue = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME>::CppType;
+ using StorageValue =
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME>::StorageType;
using PrimitiveValue = typename
PrimitiveTypeTraits<TYPE_DATETIME>::CppType;
static_assert(std::is_same_v<StorageValue, int64_t>);
-public:
static StorageValue to_storage(const PrimitiveValue& value) {
return static_cast<StorageValue>(value.to_olap_datetime());
}
+ static PrimitiveValue to_primitive(const StorageValue& value) {
+ return
PrimitiveValue::create_from_olap_datetime(static_cast<uint64_t>(value));
+ }
static const uint8_t* column_to_storage(const IColumn& column, size_t
row_pos, size_t n,
StorageBuffers& buffers);
+ static void storage_to_column(const uint8_t* values, size_t n, IColumn&
dst);
};
// V1 DECIMAL: the integer and the nine-digit fraction stored side by side.
template <>
struct StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL> {
-private:
- using StorageValue = typename
CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL>::CppType;
+ using StorageValue =
+ typename
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL>::StorageType;
using PrimitiveValue = typename
PrimitiveTypeTraits<TYPE_DECIMALV2>::CppType;
static_assert(std::is_same_v<StorageValue, decimal12_t>);
-public:
static StorageValue to_storage(const PrimitiveValue& value) {
return {value.int_value(), value.frac_value()};
}
+ static PrimitiveValue to_primitive(const StorageValue& value) {
+ return PrimitiveValue(value.integer, value.fraction);
+ }
static const uint8_t* column_to_storage(const IColumn& column, size_t
row_pos, size_t n,
StorageBuffers& buffers);
+ static void storage_to_column(const uint8_t* values, size_t n, IColumn&
dst);
};
template <>
diff --git a/be/src/storage/types.h b/be/src/storage/types.h
index fc3602f0df6..d7e806ebf2e 100644
--- a/be/src/storage/types.h
+++ b/be/src/storage/types.h
@@ -59,189 +59,189 @@ static const std::vector<std::string> DATE_FORMATS {
// ARRAY / MAP / STRUCT are intentionally NOT specialized here: they are
// containers of other types, so only their element types have a storage-layer
// cell representation. The primary template below uses a deferred
-// static_assert so that instantiating `CppTypeTraits<X>` for any
+// static_assert so that instantiating `StorageTypeTraits<X>` for any
// unspecialized FieldType — most importantly ARRAY/MAP/STRUCT — fails at
// build time with a clear message, rather than at runtime.
namespace detail {
template <FieldType>
-inline constexpr bool cpp_type_traits_unspecialized = false;
+inline constexpr bool storage_type_traits_unspecialized = false;
} // namespace detail
template <FieldType field_type>
-struct CppTypeTraits {
- static_assert(detail::cpp_type_traits_unspecialized<field_type>,
- "CppTypeTraits not specialized for this FieldType. "
+struct StorageTypeTraits {
+ static_assert(detail::storage_type_traits_unspecialized<field_type>,
+ "StorageTypeTraits not specialized for this FieldType. "
"ARRAY / MAP / STRUCT and similar container types have no "
"storage-layer cell representation — operate on the element "
"type instead.");
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_BOOL> {
- using CppType = uint8_t;
- using UnsignedCppType = uint8_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_BOOL> {
+ using StorageType = uint8_t;
+ using UnsignedStorageType = uint8_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TINYINT> {
- using CppType = int8_t;
- using UnsignedCppType = uint8_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TINYINT> {
+ using StorageType = int8_t;
+ using UnsignedStorageType = uint8_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_SMALLINT> {
- using CppType = int16_t;
- using UnsignedCppType = uint16_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_SMALLINT> {
+ using StorageType = int16_t;
+ using UnsignedStorageType = uint16_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_INT> {
- using CppType = int32_t;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_INT> {
+ using StorageType = int32_t;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT> {
- using CppType = uint32_t;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT> {
+ using StorageType = uint32_t;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_BIGINT> {
- using CppType = int64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_BIGINT> {
+ using StorageType = int64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT> {
- using CppType = uint64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT> {
+ using StorageType = uint64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_LARGEINT> {
- using CppType = int128_t;
- using UnsignedCppType = uint128_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_LARGEINT> {
+ using StorageType = int128_t;
+ using UnsignedStorageType = uint128_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_FLOAT> {
- using CppType = float;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_FLOAT> {
+ using StorageType = float;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DOUBLE> {
- using CppType = double;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DOUBLE> {
+ using StorageType = double;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL> {
- using CppType = decimal12_t;
- using UnsignedCppType = decimal12_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL> {
+ using StorageType = decimal12_t;
+ using UnsignedStorageType = decimal12_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL32> {
- using CppType = int32_t;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL32> {
+ using StorageType = int32_t;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL64> {
- using CppType = int64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL64> {
+ using StorageType = int64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL128I> {
- using CppType = int128_t;
- using UnsignedCppType = uint128_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL128I> {
+ using StorageType = int128_t;
+ using UnsignedStorageType = uint128_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL256> {
- using CppType = wide::Int256;
- using UnsignedCppType = wide::UInt256;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DECIMAL256> {
+ using StorageType = wide::Int256;
+ using UnsignedStorageType = wide::UInt256;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE> {
- using CppType = uint24_t;
- using UnsignedCppType = uint24_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE> {
+ using StorageType = uint24_t;
+ using UnsignedStorageType = uint24_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2> {
- using CppType = uint32_t;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATEV2> {
+ using StorageType = uint32_t;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMEV2> {
- using CppType = uint64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMEV2> {
+ using StorageType = uint64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2> {
- using CppType = uint64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIMEV2> {
+ using StorageType = uint64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMP_NS> {
- using CppType = int64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMP_NS> {
+ using StorageType = int64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ> {
- using CppType = uint64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ> {
+ using StorageType = uint64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME> {
- using CppType = int64_t;
- using UnsignedCppType = uint64_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATETIME> {
+ using StorageType = int64_t;
+ using UnsignedStorageType = uint64_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_IPV4> {
- using CppType = uint32_t;
- using UnsignedCppType = uint32_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_IPV4> {
+ using StorageType = uint32_t;
+ using UnsignedStorageType = uint32_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_IPV6> {
- using CppType = uint128_t;
- using UnsignedCppType = uint128_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_IPV6> {
+ using StorageType = uint128_t;
+ using UnsignedStorageType = uint128_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_UUID> {
- using CppType = uint128_t;
- using UnsignedCppType = uint128_t;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_UUID> {
+ using StorageType = uint128_t;
+ using UnsignedStorageType = uint128_t;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_CHAR> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_CHAR> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_VARCHAR> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_VARCHAR> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_STRING> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_STRING> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_JSONB> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_JSONB> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_VARIANT> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_VARIANT> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_HLL> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_HLL> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_BITMAP> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_BITMAP> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE> {
+ using StorageType = Slice;
};
template <>
-struct CppTypeTraits<FieldType::OLAP_FIELD_TYPE_AGG_STATE> {
- using CppType = Slice;
+struct StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_AGG_STATE> {
+ using StorageType = Slice;
};
template <FieldType field_type>
-struct BaseFieldTypeTraits : public CppTypeTraits<field_type> {
- using CppType = typename CppTypeTraits<field_type>::CppType;
+struct BaseFieldTypeTraits : public StorageTypeTraits<field_type> {
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
static inline CppType get_cpp_type_value(const void* address) {
if constexpr (field_type == FieldType::OLAP_FIELD_TYPE_LARGEINT) {
@@ -271,7 +271,7 @@ struct BaseFieldTypeTraits : public
CppTypeTraits<field_type> {
// FieldType::OLAP_FIELD_TYPE_DOUBLE, to reduce redundant code
template <FieldType fieldType, bool isArithmetic>
struct NumericFieldTypeTraits : public BaseFieldTypeTraits<fieldType> {
- using CppType = typename CppTypeTraits<fieldType>::CppType;
+ using CppType = typename StorageTypeTraits<fieldType>::StorageType;
};
template <FieldType fieldType>
@@ -386,14 +386,14 @@ struct
FieldTypeTraits<FieldType::OLAP_FIELD_TYPE_AGG_STATE>
// Instantiate this template to get static access to the type traits.
template <FieldType field_type>
struct TypeTraits : public FieldTypeTraits<field_type> {
- using CppType = typename CppTypeTraits<field_type>::CppType;
+ using CppType = typename StorageTypeTraits<field_type>::StorageType;
static const FieldType type = field_type;
static const int32_t size = sizeof(CppType);
};
// In-memory storage cell footprint for one value of `field_type`,
-// i.e. sizeof(CppTypeTraits<field_type>::CppType).
+// i.e. sizeof(StorageTypeTraits<field_type>::StorageType).
//
// This is NOT the schema-declared length:
// - CHAR(N) / VARCHAR(N) / STRING / JSONB / VARIANT / HLL / BITMAP /
@@ -417,7 +417,7 @@ inline size_t field_type_size(FieldType field_type) {
switch (field_type) {
#define DORIS_FIELD_TYPE_SIZE_CASE(ft) \
case FieldType::ft: \
- return sizeof(typename CppTypeTraits<FieldType::ft>::CppType);
+ return sizeof(typename StorageTypeTraits<FieldType::ft>::StorageType);
DORIS_FIELD_TYPE_SIZE_CASE(OLAP_FIELD_TYPE_BOOL)
DORIS_FIELD_TYPE_SIZE_CASE(OLAP_FIELD_TYPE_TINYINT)
DORIS_FIELD_TYPE_SIZE_CASE(OLAP_FIELD_TYPE_SMALLINT)
diff --git a/be/test/core/column/column_array_test.cpp
b/be/test/core/column/column_array_test.cpp
index e0dd2c6febe..13d532536d4 100644
--- a/be/test/core/column/column_array_test.cpp
+++ b/be/test/core/column/column_array_test.cpp
@@ -365,15 +365,6 @@ protected:
};
//////////////////////// basic function from column.h ////////////////////////
-TEST_F(ColumnArrayTest, InsertManyFixLengthDataTest) {
- auto callback = [&](MutableColumns& load_cols, DataTypeSerDeSPtrs serders)
{
- for (auto& col : array_columns) {
- EXPECT_ANY_THROW(col->insert_many_fix_len_data(nullptr, 0));
- }
- };
- assert_insert_many_fix_len_data(array_columns, serdes, callback);
-}
-
TEST_F(ColumnArrayTest, InsertManyDictDataTest) {
auto callback = [&](MutableColumns& load_cols, DataTypeSerDeSPtrs serders)
{
for (auto& col : array_columns) {
diff --git a/be/test/core/column/column_decimal_test.cpp
b/be/test/core/column/column_decimal_test.cpp
index 01beb71e360..ca4cffa0cab 100644
--- a/be/test/core/column/column_decimal_test.cpp
+++ b/be/test/core/column/column_decimal_test.cpp
@@ -238,12 +238,6 @@ TEST_F(ColumnDecimalTest, insert_indices_from) {
_column_decimal_common_test_with_type(assert_column_vector_insert_indices_from_callback,
false);
}
-// decimal, vector, nullable, PredicateColumnType
-TEST_F(ColumnDecimalTest, insert_many_fix_len_data) {
-
_column_decimal_common_test_with_type(assert_column_vector_insert_many_fix_len_data_callback,
- true);
-}
-
TEST_F(ColumnDecimalTest, insert_many_raw_data) {
_column_decimal_common_test_with_type(assert_column_vector_insert_many_raw_data_callback,
false);
diff --git a/be/test/core/column/column_vector_test.cpp
b/be/test/core/column/column_vector_test.cpp
index 1517a2df370..0552a7e7271 100644
--- a/be/test/core/column/column_vector_test.cpp
+++ b/be/test/core/column/column_vector_test.cpp
@@ -249,30 +249,6 @@ TEST_F(ColumnVectorTest, insert_range_of_integer) {
assert_column_vector_insert_range_of_integer_callback<TYPE_DOUBLE>((Float64)0,
column_float64->get_ptr());
}
-// void insert_date_column(const char* data_ptr, size_t num) {
-// decimal, vector, nullable, PredicateColumnType
-TEST_F(ColumnVectorTest, insert_many_fix_len_data) {
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_TINYINT>((Int8)0,
-
column_int8->get_ptr());
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_SMALLINT>((Int16)0,
-
column_int16->get_ptr());
- assert_column_vector_insert_many_fix_len_data_callback<TYPE_INT>((Int32)0,
-
column_int32->get_ptr());
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_BIGINT>((Int64)0,
-
column_int64->get_ptr());
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_LARGEINT>((Int128)0,
-
column_int128->get_ptr());
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_BOOLEAN>((UInt8)0,
-
column_uint8->get_ptr());
- assert_column_vector_insert_many_fix_len_data_callback<TYPE_DATETIMEV2>(
- (UInt64)0, column_datetime_v2_0->get_ptr());
- assert_column_vector_insert_many_fix_len_data_callback<TYPE_DATETIMEV2>(
- (UInt64)0, column_datetime_v2_5->get_ptr());
- assert_column_vector_insert_many_fix_len_data_callback<TYPE_DATETIMEV2>(
- (UInt64)0, column_datetime_v2_6->get_ptr());
-
assert_column_vector_insert_many_fix_len_data_callback<TYPE_DATEV2>((UInt32)0,
-
column_date_v2->get_ptr());
-}
TEST_F(ColumnVectorTest, insert_many_raw_data) {
_column_vector_common_test(assert_column_vector_insert_many_raw_data_callback);
}
diff --git a/be/test/core/column/common_column_test.h
b/be/test/core/column/common_column_test.h
index 8a97ae0f10d..6320dd52aa3 100644
--- a/be/test/core/column/common_column_test.h
+++ b/be/test/core/column/common_column_test.h
@@ -264,17 +264,8 @@ public:
////////// =================== column data insert interface assert(16)
=================== //////////
// In storage layer such as segment_iterator to call these function
- // insert_many_fix_len_data (const char *pos, size_t num);
// insert_many_dict_data (const int32_t *data_array, size_t start_index,
const StringRef *dict, size_t data_num, uint32_t dict_num=0)
// insert_many_continuous_binary_data (const char *data, const uint32_t
*offsets, const size_t num)
- static void assert_insert_many_fix_len_data(
- MutableColumns& load_cols, DataTypeSerDeSPtrs serders,
- std::function<void(MutableColumns& load_cols, DataTypeSerDeSPtrs
serders)>
- assert_callback) {
- // Create a column to verify `insert_many_fix_len_data` functionality
- assert_callback(load_cols, serders);
- }
-
static void assert_insert_many_dict_data(
MutableColumns& load_cols, DataTypeSerDeSPtrs serders,
std::function<void(MutableColumns& load_cols, DataTypeSerDeSPtrs
serders)>
@@ -2836,46 +2827,6 @@ auto
assert_column_vector_insert_range_of_integer_callback = [](auto x, const Mu
}
};
template <PrimitiveType PType>
-auto assert_column_vector_insert_many_fix_len_data_callback = [](auto x, const
MutableColumnPtr&
-
source_column) {
- using T = decltype(x);
- using ColumnVecType =
- std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<PType>,
ColumnVector<PType>>;
- std::vector<size_t> insert_vals_count = {0, 10, 1000};
- auto* col_vec_src = assert_cast<ColumnVecType*>(source_column.get());
- auto src_size = source_column->size();
- std::vector<size_t> src_data_indices = {0, src_size - 1, (src_size + 1) >>
1};
-
- auto test_func = [&](size_t clone_count) {
- size_t actual_clone_count = std::min(clone_count, src_size);
- auto target_column = source_column->clone_resized(actual_clone_count);
- auto* col_vec_target =
assert_cast<ColumnVecType*>(target_column.get());
- for (auto pos = src_data_indices.begin(); pos <
src_data_indices.end(); ++pos) {
- if (*pos >= src_size) {
- continue;
- }
- for (auto n : insert_vals_count) {
- col_vec_target->resize(actual_clone_count);
- size_t actual_insert_count = std::min(n, src_size - *pos);
-
col_vec_target->insert_many_fix_len_data(source_column->get_data_at(*pos).data,
- actual_insert_count);
- auto target_size = col_vec_target->size();
- EXPECT_EQ(target_size, actual_clone_count +
actual_insert_count);
- size_t i = 0;
- for (; i < actual_clone_count; ++i) {
- EXPECT_EQ(col_vec_target->get_element(i),
col_vec_src->get_element(i));
- }
- for (size_t j = *pos; i < target_size; ++i, ++j) {
- EXPECT_EQ(col_vec_target->get_element(i),
col_vec_src->get_element(j))
- << col_vec_src->get_name() << ' ' <<
col_vec_target->get_name();
- }
- }
- }
- };
- test_func(0);
- test_func(10);
-};
-template <PrimitiveType PType>
auto assert_column_vector_insert_many_raw_data_callback = [](auto x, const
MutableColumnPtr&
source_column) {
using T = decltype(x);
diff --git a/be/test/exec/sink/writer/iceberg/partition_transformers_test.cpp
b/be/test/exec/sink/writer/iceberg/partition_transformers_test.cpp
index d73b7dd7344..673e41dac64 100644
--- a/be/test/exec/sink/writer/iceberg/partition_transformers_test.cpp
+++ b/be/test/exec/sink/writer/iceberg/partition_transformers_test.cpp
@@ -218,7 +218,7 @@ TEST_F(PartitionTransformersTest,
date_partitions_before_epoch_use_calendar_ordi
TEST_F(PartitionTransformersTest, test_integer_truncate_transform) {
const std::vector<int32_t> values({1, -1});
auto column = ColumnInt32::create();
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_int(column->get_ptr(),
std::make_shared<DataTypeInt32>(),
"test_int");
@@ -239,7 +239,7 @@ TEST_F(PartitionTransformersTest,
test_integer_truncate_transform) {
TEST_F(PartitionTransformersTest, test_bigint_truncate_transform) {
const std::vector<int64_t> values({1, -1});
auto column = ColumnInt64::create();
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_bigint(column->get_ptr(),
std::make_shared<DataTypeInt64>(),
"test_bigint");
@@ -261,7 +261,7 @@ TEST_F(PartitionTransformersTest,
test_bigint_truncate_transform) {
TEST_F(PartitionTransformersTest, test_decimal32_truncate_transform) {
const std::vector<int32_t> values({1065});
auto column = ColumnDecimal32::create(0, 2);
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_decimal32(
column->get_ptr(), std::make_shared<DataTypeDecimal32>(4, 2),
"test_decimal32");
@@ -326,7 +326,7 @@ TEST_F(PartitionTransformersTest,
test_floating_point_special_partition_value) {
TEST_F(PartitionTransformersTest, test_integer_bucket_transform) {
const std::vector<int32_t> values({34, -123}); // 2017239379, -471378254
auto column = ColumnInt32::create();
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_int(column->get_ptr(),
std::make_shared<DataTypeInt32>(),
"test_int");
@@ -347,7 +347,7 @@ TEST_F(PartitionTransformersTest,
test_integer_bucket_transform) {
TEST_F(PartitionTransformersTest, test_bigint_bucket_transform) {
const std::vector<int64_t> values({34, -123}); // 2017239379, -471378254
auto column = ColumnInt64::create();
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_bigint(column->get_ptr(),
std::make_shared<DataTypeInt64>(),
"test_bigint");
@@ -369,7 +369,7 @@ TEST_F(PartitionTransformersTest,
test_bigint_bucket_transform) {
TEST_F(PartitionTransformersTest, test_decimal32_bucket_transform) {
const std::vector<int32_t> values({1420}); // -500754589
auto column = ColumnDecimal32::create(0, 2);
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_decimal32(
column->get_ptr(), std::make_shared<DataTypeDecimal32>(4, 2),
"test_decimal32");
@@ -649,7 +649,7 @@ TEST_F(PartitionTransformersTest,
test_timestamp_hour_transform) {
TEST_F(PartitionTransformersTest, test_void_transform) {
const std::vector<int32_t> values({1, -1});
auto column = ColumnInt32::create();
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_int(column->get_ptr(),
std::make_shared<DataTypeInt32>(),
"test_int");
@@ -671,7 +671,7 @@ TEST_F(PartitionTransformersTest,
test_nullable_column_integer_truncate_transfor
const std::vector<int32_t> values({1, -1});
auto column = ColumnNullable::create(ColumnInt32::create(),
ColumnUInt8::create());
column->insert_data(nullptr, 0);
- column->insert_many_fix_len_data(reinterpret_cast<const
char*>(values.data()), values.size());
+ column->insert_many_raw_data(reinterpret_cast<const char*>(values.data()),
values.size());
ColumnWithTypeAndName test_int(
column->get_ptr(),
std::make_shared<DataTypeNullable>(std::make_shared<DataTypeInt32>()),
"test_int");
diff --git a/be/test/storage/index/date_bloom_filter_test.cpp
b/be/test/storage/index/date_bloom_filter_test.cpp
index 00703648056..e5473e52a7a 100644
--- a/be/test/storage/index/date_bloom_filter_test.cpp
+++ b/be/test/storage/index/date_bloom_filter_test.cpp
@@ -145,17 +145,13 @@ TEST_F(DateBloomFilterTest, query_index_test) {
auto date = timestamp_from_date("2024-11-08");
auto datetime = timestamp_from_datetime("2024-11-08 09:00:00");
- uint24_t olap_date_value(date.to_olap_date());
- uint64_t olap_datetime_value(datetime.to_olap_datetime());
- columns[0]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_date_value), 1);
- columns[1]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_datetime_value), 1);
+ columns[0]->insert_data(reinterpret_cast<const char*>(&date),
sizeof(date));
+ columns[1]->insert_data(reinterpret_cast<const char*>(&datetime),
sizeof(datetime));
date = timestamp_from_date("2024-11-09");
datetime = timestamp_from_datetime("2024-11-09 09:00:00");
- olap_date_value = date.to_olap_date();
- olap_datetime_value = datetime.to_olap_datetime();
- columns[0]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_date_value), 1);
- columns[1]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_datetime_value), 1);
+ columns[0]->insert_data(reinterpret_cast<const char*>(&date),
sizeof(date));
+ columns[1]->insert_data(reinterpret_cast<const char*>(&datetime),
sizeof(datetime));
block.set_columns(std::move(columns));
Status st;
@@ -242,17 +238,13 @@ TEST_F(DateBloomFilterTest, in_list_predicate_test) {
// Insert test data
auto date = timestamp_from_date("2024-11-08");
auto datetime = timestamp_from_datetime("2024-11-08 09:00:00");
- uint24_t olap_date_value(date.to_olap_date());
- uint64_t olap_datetime_value(datetime.to_olap_datetime());
- columns[0]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_date_value), 1);
- columns[1]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_datetime_value), 1);
+ columns[0]->insert_data(reinterpret_cast<const char*>(&date),
sizeof(date));
+ columns[1]->insert_data(reinterpret_cast<const char*>(&datetime),
sizeof(datetime));
date = timestamp_from_date("2024-11-09");
datetime = timestamp_from_datetime("2024-11-09 09:00:00");
- olap_date_value = date.to_olap_date();
- olap_datetime_value = datetime.to_olap_datetime();
- columns[0]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_date_value), 1);
- columns[1]->insert_many_fix_len_data(reinterpret_cast<const
char*>(&olap_datetime_value), 1);
+ columns[0]->insert_data(reinterpret_cast<const char*>(&date),
sizeof(date));
+ columns[1]->insert_data(reinterpret_cast<const char*>(&datetime),
sizeof(datetime));
block.set_columns(std::move(columns));
EXPECT_TRUE(rowset_writer->add_block(&block).ok());
diff --git a/be/test/storage/index/index_builder_test.cpp
b/be/test/storage/index/index_builder_test.cpp
index 746d93536e3..40e70cc1dd7 100644
--- a/be/test/storage/index/index_builder_test.cpp
+++ b/be/test/storage/index/index_builder_test.cpp
@@ -3648,7 +3648,7 @@ TEST_F(IndexBuilderTest,
BuildIndexReusesStringDescriptorsAcrossNullRuns) {
TEST_F(IndexBuilderTest,
FloatingPointBuildIndexBorrowsCleanRunsAndPreservesSource) {
auto check = [&]<FieldType FT>() {
- using Value = typename CppTypeTraits<FT>::CppType;
+ using Value = typename StorageTypeTraits<FT>::StorageType;
using UInt = std::conditional_t<sizeof(Value) == sizeof(uint32_t),
uint32_t, uint64_t>;
using Column =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::ColumnType;
diff --git a/be/test/storage/index/inverted/snii/bkd/bkd_differential_test.cpp
b/be/test/storage/index/inverted/snii/bkd/bkd_differential_test.cpp
index 359b9121401..f315d003eed 100644
--- a/be/test/storage/index/inverted/snii/bkd/bkd_differential_test.cpp
+++ b/be/test/storage/index/inverted/snii/bkd/bkd_differential_test.cpp
@@ -101,7 +101,7 @@ struct Dataset {
// everything downstream is type-agnostic bytes.
template <FieldType FT>
struct ValueFactory {
- using CppType = typename CppTypeTraits<FT>::CppType;
+ using CppType = typename StorageTypeTraits<FT>::StorageType;
// A deterministic mapping from a rank to a value, injective wherever the
// domain allows it. Narrow types (BOOL, TINYINT) wrap, which is a
legitimate
@@ -158,7 +158,7 @@ struct ValueFactory {
// construction, and that is asserted rather than assumed: a KeyCoder whose
// output is not sizeof(CppType) would silently break INV-2 for every case
below.
template <FieldType FT>
-Bytes encode(const typename CppTypeTraits<FT>::CppType& value) {
+Bytes encode(const typename StorageTypeTraits<FT>::StorageType& value) {
Bytes buf;
get_key_coder(FT)->full_encode_ascending(&value, &buf);
EXPECT_EQ(buf.size(), field_type_size(FT));
diff --git a/be/test/storage/index/inverted/snii/bkd/bkd_property_test.cpp
b/be/test/storage/index/inverted/snii/bkd/bkd_property_test.cpp
index c0ae37dda20..2ef27ced5e7 100644
--- a/be/test/storage/index/inverted/snii/bkd/bkd_property_test.cpp
+++ b/be/test/storage/index/inverted/snii/bkd/bkd_property_test.cpp
@@ -107,7 +107,7 @@ constexpr uint32_t kLeafCapacities[] = {1, 2, 5, 16, 1024};
// construction, and that is asserted rather than assumed: a KeyCoder emitting
// something other than sizeof(CppType) would silently break INV-2.
template <FieldType FT>
-Bytes encode(const typename CppTypeTraits<FT>::CppType& value) {
+Bytes encode(const typename StorageTypeTraits<FT>::StorageType& value) {
Bytes buf;
get_key_coder(FT)->full_encode_ascending(&value, &buf);
EXPECT_EQ(buf.size(), field_type_size(FT));
@@ -119,7 +119,7 @@ Bytes encode(const typename CppTypeTraits<FT>::CppType&
value) {
// repeats across thousands of points and dozens of leaves.
template <FieldType FT>
Bytes encode_rank(int64_t rank) {
- using CppType = typename CppTypeTraits<FT>::CppType;
+ using CppType = typename StorageTypeTraits<FT>::StorageType;
return encode<FT>(static_cast<CppType>(rank));
}
@@ -672,8 +672,8 @@ TYPED_TEST(BkdPropertyTest,
BuildIsDeterministicUnderPerDocValueOrder) {
// Check encoded ranges against native value order across signed, unsigned,
and floating-point types.
template <FieldType FT>
-std::vector<typename CppTypeTraits<FT>::CppType> native_spread() {
- using CppType = typename CppTypeTraits<FT>::CppType;
+std::vector<typename StorageTypeTraits<FT>::StorageType> native_spread() {
+ using CppType = typename StorageTypeTraits<FT>::StorageType;
std::vector<CppType> values;
if constexpr (std::is_floating_point_v<CppType>) {
// Negative zero is deliberate: it must not sort strictly below +0.0
nor
@@ -685,7 +685,7 @@ std::vector<typename CppTypeTraits<FT>::CppType>
native_spread() {
values.push_back(std::numeric_limits<CppType>::lowest());
values.push_back(std::numeric_limits<CppType>::max());
} else {
- using UnsignedType = typename CppTypeTraits<FT>::UnsignedCppType;
+ using UnsignedType = typename
StorageTypeTraits<FT>::UnsignedStorageType;
constexpr size_t kBits = sizeof(CppType) * 8;
constexpr bool kIsSigned = std::is_signed_v<CppType>;
const CppType lo = kIsSigned ? static_cast<CppType>(UnsignedType(1) <<
(kBits - 1))
diff --git
a/be/test/storage/index/inverted/snii/snii_bkd_adapter_types_test.cpp
b/be/test/storage/index/inverted/snii/snii_bkd_adapter_types_test.cpp
index 57797bb151f..44cea68bbb5 100644
--- a/be/test/storage/index/inverted/snii/snii_bkd_adapter_types_test.cpp
+++ b/be/test/storage/index/inverted/snii/snii_bkd_adapter_types_test.cpp
@@ -64,7 +64,7 @@ struct FieldTag {
// correct way rather than reinvented here.
template <FieldType FT>
struct ValueOf {
- using CppType = typename CppTypeTraits<FT>::CppType;
+ using CppType = typename StorageTypeTraits<FT>::StorageType;
static CppType from_rank(int64_t rank) {
if constexpr (std::is_same_v<CppType, decimal12_t>) {
decimal12_t value;
@@ -125,7 +125,7 @@ TYPED_TEST_SUITE(SniiBkdAdapterTypesTest, FieldTypeTags);
TYPED_TEST(SniiBkdAdapterTypesTest, AdapterPreservesValueToRowAssociation) {
constexpr FieldType FT = TypeParam::kFieldType;
- using CppType = typename CppTypeTraits<FT>::CppType;
+ using CppType = typename StorageTypeTraits<FT>::StorageType;
// 240 rows over 60 distinct ranks, so most values own several rows and a
// shifted-by-one stride cannot coincidentally reproduce the mapping.
diff --git a/be/test/storage/key_coder_test.cpp
b/be/test/storage/key_coder_test.cpp
index ee14881ca42..43d56d2de72 100644
--- a/be/test/storage/key_coder_test.cpp
+++ b/be/test/storage/key_coder_test.cpp
@@ -45,7 +45,7 @@ public:
template <FieldType type>
void test_integer_encode() {
- using CppType = typename CppTypeTraits<type>::CppType;
+ using CppType = typename StorageTypeTraits<type>::StorageType;
auto key_coder = get_key_coder(type);
@@ -111,9 +111,9 @@ void test_integer_encode() {
}
template <FieldType field_type>
-typename CppTypeTraits<field_type>::CppType decode_float(const std::string&
encoded) {
+typename StorageTypeTraits<field_type>::StorageType decode_float(const
std::string& encoded) {
Slice encoded_key(encoded);
- typename CppTypeTraits<field_type>::CppType result;
+ typename StorageTypeTraits<field_type>::StorageType result;
uint8_t* ptr = reinterpret_cast<uint8_t*>(&result);
Status status = KeyCoderTraits<field_type>::decode_ascending(&encoded_key,
sizeof(result), ptr);
EXPECT_TRUE(status.ok());
@@ -121,22 +121,23 @@ typename CppTypeTraits<field_type>::CppType
decode_float(const std::string& enco
}
template <FieldType field_type>
-std::string encode_float(typename CppTypeTraits<field_type>::CppType value) {
+std::string encode_float(typename StorageTypeTraits<field_type>::StorageType
value) {
std::string buf;
KeyCoderTraits<field_type>::full_encode_ascending(&value, &buf);
return buf;
}
template <FieldType field_type>
-void test_encode_decode(typename CppTypeTraits<field_type>::CppType value) {
+void test_encode_decode(typename StorageTypeTraits<field_type>::StorageType
value) {
std::string encoded = encode_float<field_type>(value);
- typename CppTypeTraits<field_type>::CppType decoded =
decode_float<field_type>(encoded);
+ typename StorageTypeTraits<field_type>::StorageType decoded =
decode_float<field_type>(encoded);
EXPECT_EQ(value, decoded);
}
template <FieldType field_type>
-void test_ordering(typename CppTypeTraits<field_type>::CppType a,
- typename CppTypeTraits<field_type>::CppType b) {
+// NOLINTNEXTLINE(readability-function-cognitive-complexity) -- GTest
assertion macros inflate it.
+void test_ordering(typename StorageTypeTraits<field_type>::StorageType a,
+ typename StorageTypeTraits<field_type>::StorageType b) {
std::string encoded_a = encode_float<field_type>(a);
std::string encoded_b = encode_float<field_type>(b);
@@ -907,7 +908,7 @@ void WriteStringToFile(std::ofstream& out, const
std::string& value, FieldType f
// Helper function to read from file and decode
template <FieldType field_type>
void ReadAndDecodeNumber(std::ifstream& in) {
- using T = typename CppTypeTraits<field_type>::CppType;
+ using T = typename StorageTypeTraits<field_type>::StorageType;
// 2. read original_value
size_t value_size = 0;
@@ -974,7 +975,7 @@ void ReadAndDecodeString(std::ifstream& in) {
template <FieldType field_type>
void WriteAllBoundaryValues(std::ofstream& out) {
- using T = typename CppTypeTraits<field_type>::CppType;
+ using T = typename StorageTypeTraits<field_type>::StorageType;
WriteNumberToFile<T>(out, std::numeric_limits<T>::min(), field_type);
WriteNumberToFile<T>(out, T(0), field_type);
WriteNumberToFile<T>(out, std::numeric_limits<T>::max(), field_type);
@@ -994,7 +995,7 @@ void WriteStringsValues(std::ofstream& out, const
std::string& str) {
template <FieldType field_type>
void WriteFloatValues(std::ofstream& out) {
- using T = typename CppTypeTraits<field_type>::CppType;
+ using T = typename StorageTypeTraits<field_type>::StorageType;
WriteNumberToFile<T>(out, +0.0, field_type);
WriteNumberToFile<T>(out, -0.0, field_type);
WriteNumberToFile<T>(out, 1.0, field_type);
@@ -1209,7 +1210,7 @@ void WriteSingleValueToComplexFile(std::ofstream& out) {
out.write(reinterpret_cast<const char*>(&value), value_size);
} else if constexpr (field_is_numeric_type(field_type) ||
field_type ==
FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT) {
- using T = typename CppTypeTraits<field_type>::CppType;
+ using T = typename StorageTypeTraits<field_type>::StorageType;
T value = std::numeric_limits<T>::min();
size_t value_size = sizeof(value);
out.write(reinterpret_cast<const char*>(&value_size),
sizeof(value_size));
@@ -1248,7 +1249,7 @@ void WriteSingleEncodedValueToComplexFile(std::ofstream&
out) {
coder->full_encode_ascending(&value, &encoded_buf);
} else if constexpr (field_is_numeric_type(field_type) ||
field_type ==
FieldType::OLAP_FIELD_TYPE_UNSIGNED_BIGINT) {
- using T = typename CppTypeTraits<field_type>::CppType;
+ using T = typename StorageTypeTraits<field_type>::StorageType;
T value = std::numeric_limits<T>::min();
coder->full_encode_ascending(&value, &encoded_buf);
} else if constexpr (field_is_slice_type(field_type)) {
@@ -1392,7 +1393,7 @@ void ReadAndDecodeFromComplexFile(std::ifstream& in) {
std::string value_i(value_size_i, '\0');
in.read(value_i.data(), value_size_i);
- using T = typename CppTypeTraits<field_type_j>::CppType;
+ using T = typename StorageTypeTraits<field_type_j>::StorageType;
size_t value_size = 0;
in.read(reinterpret_cast<char*>(&value_size), sizeof(value_size));
@@ -1420,7 +1421,7 @@ void ReadAndDecodeFromComplexFile(std::ifstream& in) {
EXPECT_TRUE(status.ok());
EXPECT_EQ(decoded_value, original_value);
} else if constexpr (!field_is_slice_type(field_type_i) &&
field_is_slice_type(field_type_j)) {
- using T = typename CppTypeTraits<field_type_i>::CppType;
+ using T = typename StorageTypeTraits<field_type_i>::StorageType;
size_t value_size = 0;
in.read(reinterpret_cast<char*>(&value_size), sizeof(value_size));
@@ -1456,8 +1457,8 @@ void ReadAndDecodeFromComplexFile(std::ifstream& in) {
EXPECT_TRUE(status.ok());
EXPECT_EQ(decoded_value, original_value);
} else {
- using T = typename CppTypeTraits<field_type_i>::CppType;
- using U = typename CppTypeTraits<field_type_j>::CppType;
+ using T = typename StorageTypeTraits<field_type_i>::StorageType;
+ using U = typename StorageTypeTraits<field_type_j>::StorageType;
size_t value_size_i;
in.read(reinterpret_cast<char*>(&value_size_i), sizeof(value_size_i));
T original_value_i;
diff --git a/be/test/storage/olap_type_test.cpp
b/be/test/storage/olap_type_test.cpp
index c32ec5b7b7e..020f82f1add 100644
--- a/be/test/storage/olap_type_test.cpp
+++ b/be/test/storage/olap_type_test.cpp
@@ -33,6 +33,7 @@
#include "exprs/function/cast/cast_to_string.h"
#include "gtest/gtest_pred_impl.h"
#include "storage/olap_common.h"
+#include "storage/storage_layout_test_util.h"
namespace doris {
@@ -1119,8 +1120,7 @@ TEST_F(OlapTypeTest, char_type_with_padding) {
expected.append(15, '\0');
std::string expected_serde = expected;
- auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
- StringRef(olap_value.data, olap_value.size));
+ auto field = Field::create_field<TYPE_CHAR>(String(olap_value.data,
olap_value.size));
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
'hello'"
@@ -1136,8 +1136,7 @@ TEST_F(OlapTypeTest, char_type_with_padding) {
std::string expected(20, 'x');
std::string expected_serde = expected;
- auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
- StringRef(olap_value.data, olap_value.size));
+ auto field = Field::create_field<TYPE_CHAR>(String(olap_value.data,
olap_value.size));
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
filled 'x'";
@@ -1151,8 +1150,7 @@ TEST_F(OlapTypeTest, char_type_with_padding) {
std::string expected(20, '\0');
std::string expected_serde = expected;
- auto field = Field::create_field_from_olap_value<TYPE_CHAR>(
- StringRef(olap_value.data, olap_value.size));
+ auto field = Field::create_field<TYPE_CHAR>(String(olap_value.data,
olap_value.size));
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for CHAR(20)
empty"
@@ -1179,8 +1177,7 @@ TEST_F(OlapTypeTest, varchar_type) {
for (auto& tc : test_cases) {
Slice olap_value(tc.input.data(), tc.input.size());
- auto field = Field::create_field_from_olap_value<TYPE_VARCHAR>(
- StringRef(olap_value.data, olap_value.size));
+ auto field = Field::create_field<TYPE_VARCHAR>(String(olap_value.data,
olap_value.size));
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1211,7 +1208,7 @@ TEST_F(OlapTypeTest, date_v1_type) {
for (auto& tc : test_cases) {
uint24_t olap_value = make_olap_date(tc.year, tc.month, tc.day);
- auto field =
Field::create_field_from_olap_value<TYPE_DATE>(olap_value);
+ auto field = field_of_cell<TYPE_DATE>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for DATE "
<< tc.expected;
@@ -1235,7 +1232,7 @@ TEST_F(OlapTypeTest, datetime_v1_type) {
};
for (auto& tc : test_cases) {
- auto field =
Field::create_field_from_olap_value<TYPE_DATETIME>((uint64_t)tc.olap_value);
+ auto field = field_of_cell<TYPE_DATETIME>((uint64_t)tc.olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for
DATETIME " << tc.expected;
@@ -1265,7 +1262,7 @@ TEST_F(OlapTypeTest, datev2_type) {
for (auto& tc : test_cases) {
uint32_t olap_value = make_datev2(tc.year, tc.month, tc.day);
- auto field =
Field::create_field_from_olap_value<TYPE_DATEV2>(olap_value);
+ auto field = field_of_cell<TYPE_DATEV2>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str) << "serde mismatch for DATEV2
" << tc.expected;
@@ -1307,7 +1304,7 @@ TEST_F(OlapTypeTest, datetimev2_type) {
auto serde = data_type->get_serde();
for (auto& tc : test_cases) {
- auto field =
Field::create_field_from_olap_value<TYPE_DATETIMEV2>(tc.olap_value);
+ auto field = field_of_cell<TYPE_DATETIMEV2>(tc.olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected, serde_str)
@@ -1325,7 +1322,7 @@ TEST_F(OlapTypeTest,
datetime_v1_vs_v2_precision_difference) {
int64_t olap_value = 20230615123456L;
std::string expected = "2023-06-15 12:34:56";
std::string expected_serde = expected;
- auto field =
Field::create_field_from_olap_value<TYPE_DATETIME>((uint64_t)olap_value);
+ auto field = field_of_cell<TYPE_DATETIME>((uint64_t)olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for DATETIME
V1";
@@ -1347,7 +1344,7 @@ TEST_F(OlapTypeTest,
datetime_v1_vs_v2_precision_difference) {
uint64_t olap_value = make_datetimev2(2023, 6, 15, 12, 34, 56, 123456);
std::string expected = "2023-06-15 12:34:56.123456";
std::string expected_serde = expected;
- auto field =
Field::create_field_from_olap_value<TYPE_DATETIMEV2>(olap_value);
+ auto field = field_of_cell<TYPE_DATETIMEV2>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(expected_serde, serde_str) << "serde mismatch for
DATETIMEV2";
@@ -1394,7 +1391,7 @@ TEST_F(OlapTypeTest, decimalv2_type) {
olap_value.integer = tc.integer;
olap_value.fraction = tc.fraction;
- auto field =
Field::create_field_from_olap_value<TYPE_DECIMALV2>(olap_value);
+ auto field = field_of_cell<TYPE_DECIMALV2>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1428,7 +1425,7 @@ TEST_F(OlapTypeTest, decimal32_type) {
auto serde = data_type->get_serde();
int32_t olap_value = tc.value;
- auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL32>(olap_value);
+ auto field = field_of_cell<TYPE_DECIMAL32>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1460,7 +1457,7 @@ TEST_F(OlapTypeTest, decimal64_type) {
auto serde = data_type->get_serde();
int64_t olap_value = tc.value;
- auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL64>(olap_value);
+ auto field = field_of_cell<TYPE_DECIMAL64>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1492,7 +1489,7 @@ TEST_F(OlapTypeTest, decimal128i_type) {
auto serde = data_type->get_serde();
int128_t olap_value = tc.value;
- auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL128I>(olap_value);
+ auto field = field_of_cell<TYPE_DECIMAL128I>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1521,7 +1518,7 @@ TEST_F(OlapTypeTest, decimal256_type) {
auto serde = data_type->get_serde();
wide::Int256 olap_value = tc.value;
- auto field =
Field::create_field_from_olap_value<TYPE_DECIMAL256>(olap_value);
+ auto field = field_of_cell<TYPE_DECIMAL256>(olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
@@ -1859,7 +1856,7 @@ TEST_F(OlapTypeTest, timestamptz_type) {
};
for (auto& tc : test_cases) {
- auto field =
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(tc.olap_value);
+ auto field = field_of_cell<TYPE_TIMESTAMPTZ>(tc.olap_value);
std::string serde_str = serde->to_olap_string(field);
EXPECT_EQ(tc.expected_serde, serde_str)
diff --git a/be/test/storage/row_cursor_test.cpp
b/be/test/storage/row_cursor_test.cpp
index 31e88ab2b4f..333912a2246 100644
--- a/be/test/storage/row_cursor_test.cpp
+++ b/be/test/storage/row_cursor_test.cpp
@@ -31,6 +31,7 @@
#include "core/uint24.h"
#include "core/wide_integer.h"
#include "storage/schema.h"
+#include "storage/storage_layout_test_util.h"
#include "storage/tablet/tablet_schema.h"
#include "storage/tablet/tablet_schema_helper.h"
#include "util/debug_util.h"
@@ -433,8 +434,7 @@ TEST_F(TestRowCursor, encode_key_int_date_varchar) {
row.mutable_field(0) = Field::create_field<TYPE_INT>(int32_t(12345));
// DATE(2020-01-01): raw uint24_t = 2020*512 + 1*32 + 1 = 1034273
- row.mutable_field(1) =
- Field::create_field_from_olap_value<TYPE_DATE>(uint24_t(2020 * 512
+ 1 * 32 + 1));
+ row.mutable_field(1) = field_of_cell<TYPE_DATE>(uint24_t(2020 * 512 + 1 *
32 + 1));
row.mutable_field(2) = Field::create_field<TYPE_STRING>(String("hello"));
// encode_key: VARCHAR('hello') truncated to 4 bytes
@@ -469,7 +469,7 @@ TEST_F(TestRowCursor, encode_key_double_nan_decimal_string)
{
Field::create_field<TYPE_DOUBLE>(std::numeric_limits<double>::quiet_NaN());
// DECIMAL(123.456000000): stored as decimal12_t{123, 456000000}
row.mutable_field(1) =
- Field::create_field_from_olap_value<TYPE_DECIMALV2>(decimal12_t
{123, 456000000});
+ field_of_cell<TYPE_DECIMALV2>(decimal12_t {.integer = 123,
.fraction = 456000000});
row.mutable_field(2) = Field::create_field<TYPE_STRING>(String("hello
world"));
// encode_key: STRING truncated to 4 bytes
@@ -541,8 +541,7 @@ TEST_F(TestRowCursor,
encode_key_float_inf_datetime_varchar) {
row.mutable_field(0) =
Field::create_field<TYPE_FLOAT>(std::numeric_limits<float>::infinity());
// DATETIME(2020-01-01 12:00:00) = 20200101120000 in olap datetime format
- row.mutable_field(1) =
-
Field::create_field_from_olap_value<TYPE_DATETIME>(uint64_t(20200101120000ULL));
+ row.mutable_field(1) =
field_of_cell<TYPE_DATETIME>(int64_t(20200101120000));
row.mutable_field(2) = Field::create_field<TYPE_STRING>(String("ab"));
// encode_key: VARCHAR('ab') only 2 bytes (< index_size=4, not truncated)
@@ -610,7 +609,7 @@ TEST_F(TestRowCursor, encode_key_negative_values) {
row.mutable_field(1) = Field::create_field<TYPE_DOUBLE>(-1.0);
// DECIMAL(-123, -456000000) representing -123.456000000
row.mutable_field(2) =
- Field::create_field_from_olap_value<TYPE_DECIMALV2>(decimal12_t
{-123, -456000000});
+ field_of_cell<TYPE_DECIMALV2>(decimal12_t {.integer = -123,
.fraction = -456000000});
{
std::string buf;
@@ -706,8 +705,7 @@ TEST_F(TestRowCursor, encode_key_datetime_v1) {
{
RowCursor row;
init_row_cursor_with_nulls(row, tablet_schema, 1);
- row.mutable_field(0) =
-
Field::create_field_from_olap_value<TYPE_DATETIME>(uint64_t(20241231123045ULL));
+ row.mutable_field(0) =
field_of_cell<TYPE_DATETIME>(int64_t(20241231123045));
std::string buf;
row.encode_key(&buf, 1);
diff --git a/be/test/storage/segment/bitshuffle_page_test.cpp
b/be/test/storage/segment/bitshuffle_page_test.cpp
index 761b7a03bfd..b182279faa4 100644
--- a/be/test/storage/segment/bitshuffle_page_test.cpp
+++ b/be/test/storage/segment/bitshuffle_page_test.cpp
@@ -21,11 +21,16 @@
#include <memory>
+#include "core/assert_cast.h"
+#include "core/column/column_vector.h"
#include "core/data_type/data_type_factory.hpp"
+#include "core/uint24.h"
+#include "core/value/vdatetime_value.h"
#include "storage/segment/bitshuffle_page_pre_decoder.h"
#include "storage/segment/options.h"
#include "storage/segment/page_builder.h"
#include "storage/segment/page_decoder.h"
+#include "storage/storage_layout.h"
using doris::segment_v2::PageBuilderOptions;
using doris::OlapReaderStatistics;
@@ -162,6 +167,39 @@ public:
status = page_decoder.seek_at_or_after_value(bigger_than_biggest,
&exact_match);
EXPECT_EQ(status.code(), ENTRY_NOT_FOUND);
}
+
+ // Eight consecutive days from 2020-01-01 in one bitshuffle page of V1
DATE cells, each date
+ // stored as a uint24, unshuffled into `decoded_page` as the page cache
holds it. `page` is
+ // left pointing at the unshuffled page.
+ void build_date_v1_page(std::vector<VecDateTimeValue>* days,
+ std::unique_ptr<DataPage>* decoded_page, Slice*
page) {
+ using Layout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>;
+ constexpr size_t kRows = 8;
+ days->resize(kRows);
+ std::vector<uint24_t> cells(kRows);
+ for (size_t i = 0; i < kRows; ++i) {
+
ASSERT_TRUE((*days)[i].from_date_int64(static_cast<int64_t>(20200101 + i)));
+ cells[i] = Layout::to_storage((*days)[i]);
+ }
+ PageBuilderOptions options;
+ options.data_page_size = 256 * 1024;
+ segment_v2::PageBuilder* builder = nullptr;
+
ASSERT_TRUE(segment_v2::BitshufflePageBuilder<FieldType::OLAP_FIELD_TYPE_DATE>::create(
+ &builder, options)
+ .ok());
+ std::unique_ptr<segment_v2::PageBuilder> page_builder(builder);
+ size_t added = kRows;
+ ASSERT_TRUE(page_builder->add(reinterpret_cast<const
uint8_t*>(cells.data()), &added).ok());
+ ASSERT_EQ(added, kRows);
+ OwnedSlice encoded;
+ ASSERT_TRUE(page_builder->finish(&encoded).ok());
+ segment_v2::BitShufflePagePreDecoder pre_decoder;
+ *page = encoded.slice();
+ ASSERT_TRUE(
+ pre_decoder
+ .decode(decoded_page, page, 0, false,
segment_v2::PageTypePB::DATA_PAGE, "")
+ .ok());
+ }
};
// Test for bitshuffle block, for INT32, INT64, FLOAT, DOUBLE
@@ -363,4 +401,48 @@ TEST_F(BitShufflePageTest,
TestBitShuffleDecimal12BlockEncoderSeekValue) {
decimals.get(), size, &small_than_smallest, &bigger_than_biggest);
}
+// A V1 DATE page holds each date as a uint24 cell; a batch decodes the cells
into the dates
+// of a ColumnDate.
+TEST_F(BitShufflePageTest, TestBitShuffleDateV1DecodesIntoDates) {
+ std::vector<VecDateTimeValue> days;
+ std::unique_ptr<DataPage> decoded_page;
+ Slice page;
+ ASSERT_NO_FATAL_FAILURE(build_date_v1_page(&days, &decoded_page, &page));
+ segment_v2::PageDecoderOptions decoder_options;
+ segment_v2::BitShufflePageDecoder<FieldType::OLAP_FIELD_TYPE_DATE>
decoder(page,
+
decoder_options);
+ ASSERT_TRUE(decoder.init().ok());
+
+ MutableColumnPtr dates = ColumnDate::create();
+ size_t n = days.size();
+ ASSERT_TRUE(decoder.next_batch(&n, dates).ok());
+ ASSERT_EQ(n, days.size());
+ const auto& decoded = assert_cast<const ColumnDate&>(*dates).get_data();
+ for (size_t i = 0; i < days.size(); ++i) {
+ EXPECT_EQ(decoded[i], days[i]) << "row " << i;
+ }
+}
+
+// Rows read by id into a ColumnDate come back as their dates.
+TEST_F(BitShufflePageTest, TestBitShuffleDateV1ReadsRowIdsIntoDates) {
+ std::vector<VecDateTimeValue> days;
+ std::unique_ptr<DataPage> decoded_page;
+ Slice page;
+ ASSERT_NO_FATAL_FAILURE(build_date_v1_page(&days, &decoded_page, &page));
+ segment_v2::PageDecoderOptions decoder_options;
+ segment_v2::BitShufflePageDecoder<FieldType::OLAP_FIELD_TYPE_DATE>
decoder(page,
+
decoder_options);
+ ASSERT_TRUE(decoder.init().ok());
+
+ const segment_v2::rowid_t rowids[] = {1, 3, 6};
+ MutableColumnPtr picked = ColumnDate::create();
+ size_t n = 3;
+ ASSERT_TRUE(decoder.read_by_rowids(rowids, 0, &n, picked).ok());
+ ASSERT_EQ(n, 3);
+ const auto& picked_dates = assert_cast<const
ColumnDate&>(*picked).get_data();
+ for (size_t i = 0; i < 3; ++i) {
+ EXPECT_EQ(picked_dates[i], days[rowids[i]]) << "row id " << rowids[i];
+ }
+}
+
} // namespace doris
diff --git a/be/test/storage/segment/bloom_filter_index_reader_writer_test.cpp
b/be/test/storage/segment/bloom_filter_index_reader_writer_test.cpp
index a661eca4225..314281dfd47 100644
--- a/be/test/storage/segment/bloom_filter_index_reader_writer_test.cpp
+++ b/be/test/storage/segment/bloom_filter_index_reader_writer_test.cpp
@@ -67,7 +67,7 @@ Status write_bloom_filter_index_file(const std::string&
file_name, const void* v
size_t value_count, size_t null_count,
ColumnIndexMetaPB* index_meta,
bool use_primary_key_bloom_filter =
false, double fpp = 0.05) {
- using CppType = typename CppTypeTraits<type>::CppType;
+ using CppType = typename StorageTypeTraits<type>::StorageType;
std::string fname = dname + "/" + file_name;
auto fs = io::global_local_filesystem();
{
diff --git a/be/test/storage/segment/inverted_index_reader_test.cpp
b/be/test/storage/segment/inverted_index_reader_test.cpp
index d35f6fe3e13..11b560aabc2 100644
--- a/be/test/storage/segment/inverted_index_reader_test.cpp
+++ b/be/test/storage/segment/inverted_index_reader_test.cpp
@@ -52,6 +52,7 @@
#include "storage/index/inverted/query/scoring/collection_similarity.h"
#include "storage/index/inverted/reader/collection_statistics.h"
#include "storage/key_coder.h"
+#include "storage/storage_layout_test_util.h"
#include "storage/tablet/tablet_schema.h"
#include "storage/tablet/tablet_schema_helper.h"
#include "util/slice.h"
@@ -3718,8 +3719,9 @@ public:
EXPECT_NE(bkd_reader, nullptr);
auto run_query = [&](InvertedIndexQueryType qt, T thr) {
- using raw_t = typename PrimitiveTypeTraits<PT>::StorageFieldType;
- Field qp =
Field::create_field_from_olap_value<PT>(static_cast<raw_t>(thr));
+ using raw_t =
+ typename
StorageLayout<primitive_type_to_storage_field_type(PT)>::StorageValue;
+ Field qp = field_of_cell<PT>(static_cast<raw_t>(thr));
auto bitmap = std::make_shared<roaring::Roaring>();
auto status = bkd_reader->query(context, column_name, qp, qt,
bitmap);
EXPECT_TRUE(status.ok()) << column_name << ": " << status;
@@ -4331,8 +4333,7 @@ public:
for (auto& test_case : test_cases) {
std::shared_ptr<roaring::Roaring> bitmap =
std::make_shared<roaring::Roaring>();
- Field qp_3262 =
-
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(test_case.second);
+ Field qp_3262 =
field_of_cell<TYPE_TIMESTAMPTZ>(test_case.second);
auto status = bkd_reader->query(context, "c_timestamptz",
qp_3262, test_case.first,
bitmap);
EXPECT_TRUE(status.ok()) << "Query type: " <<
static_cast<int>(test_case.first);
@@ -4345,8 +4346,7 @@ public:
for (auto& test_case : test_cases) {
size_t count = 0;
- Field qp_3274 =
-
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(test_case.second);
+ Field qp_3274 =
field_of_cell<TYPE_TIMESTAMPTZ>(test_case.second);
auto status = bkd_reader->try_query(context, "c_timestamptz",
qp_3274,
test_case.first, &count);
EXPECT_TRUE(status.ok()) << "Try query type: " <<
static_cast<int>(test_case.first);
@@ -4444,8 +4444,8 @@ public:
uint32_t query_value = 20240102;
std::shared_ptr<roaring::Roaring> bitmap =
std::make_shared<roaring::Roaring>();
// TYPE_DATE storage is uint24_t — narrow from the test's uint32_t.
- typename PrimitiveTypeTraits<TYPE_DATE>::StorageFieldType
date_storage(query_value);
- Field qp_3366 =
Field::create_field_from_olap_value<TYPE_DATE>(date_storage);
+ const uint24_t date_storage(query_value);
+ Field qp_3366 = field_of_cell<TYPE_DATE>(date_storage);
auto status = bkd_reader->query(context, "c_date", qp_3366,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
@@ -4471,8 +4471,7 @@ public:
int64_t query_value = 20240101130000LL;
std::shared_ptr<roaring::Roaring> bitmap =
std::make_shared<roaring::Roaring>();
- Field qp_3391 = Field::create_field_from_olap_value<TYPE_DATETIME>(
- static_cast<uint64_t>(query_value));
+ Field qp_3391 = field_of_cell<TYPE_DATETIME>(query_value);
auto status = bkd_reader->query(context, "c_datetime", qp_3391,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
@@ -4651,7 +4650,7 @@ public:
uint64_t query_value = 20240201130000ULL;
std::shared_ptr<roaring::Roaring> bitmap =
std::make_shared<roaring::Roaring>();
- Field qp_3561 =
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(query_value);
+ Field qp_3561 = field_of_cell<TYPE_TIMESTAMPTZ>(query_value);
auto status = bkd_reader->query(context, "c_timestamptz", qp_3561,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
diff --git a/be/test/storage/segment/page_builder_column_test.cpp
b/be/test/storage/segment/page_builder_column_test.cpp
index 8035fb3311e..026b3c2450d 100644
--- a/be/test/storage/segment/page_builder_column_test.cpp
+++ b/be/test/storage/segment/page_builder_column_test.cpp
@@ -142,7 +142,8 @@ Pages drain(PageBuilder& builder, size_t num_rows, AddFn
add, size_t append_rows
// for a fixed-width FieldType, one Slice per row otherwise; CHAR padded to
char_length.
template <FieldType FT>
struct ReferenceCells {
- static constexpr bool kSlices = std::is_same_v<typename
CppTypeTraits<FT>::CppType, Slice>;
+ static constexpr bool kSlices =
+ std::is_same_v<typename StorageTypeTraits<FT>::StorageType, Slice>;
std::vector<uint8_t> bytes;
std::vector<Slice> slices;
@@ -168,7 +169,7 @@ struct ReferenceCells {
using Column = typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(
FT)>::ColumnType;
const auto& data = assert_cast<const Column&>(column).get_data();
- bytes.resize(n * sizeof(typename CppTypeTraits<FT>::CppType));
+ bytes.resize(n * sizeof(typename
StorageTypeTraits<FT>::StorageType));
for (size_t i = 0; i < n; ++i) {
const auto value = StorageLayout<FT>::to_storage(data[i]);
memcpy(bytes.data() + i * sizeof(value), &value,
sizeof(value));
@@ -182,7 +183,8 @@ struct ReferenceCells {
if constexpr (kSlices) {
return builder.add(reinterpret_cast<const uint8_t*>(slices.data()
+ pos), n);
} else {
- return builder.add(bytes.data() + pos * sizeof(typename
CppTypeTraits<FT>::CppType), n);
+ return builder.add(
+ bytes.data() + pos * sizeof(typename
StorageTypeTraits<FT>::StorageType), n);
}
}
};
@@ -210,7 +212,7 @@ constexpr EncodingTypePB builder_encoding() {
template <FieldType FT>
void expect_page_inputs(const RecordingPageBuilder& builder, const IColumn&
column) {
- if constexpr (std::is_floating_point_v<typename
CppTypeTraits<FT>::CppType>) {
+ if constexpr (std::is_floating_point_v<typename
StorageTypeTraits<FT>::StorageType>) {
using Column =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::ColumnType;
const auto& values = assert_cast<const Column&>(column).get_data();
@@ -260,7 +262,7 @@ void expect_same_pages(const IColumn& source,
PageBuilderOptions options, size_t
meta.set_column_id(0);
meta.set_unique_id(0);
meta.set_type(int(FT));
- meta.set_length(sizeof(typename CppTypeTraits<FT>::CppType));
+ meta.set_length(sizeof(typename StorageTypeTraits<FT>::StorageType));
meta.set_encoding(builder_encoding<Builder, FT>());
meta.set_compression(NO_COMPRESSION);
meta.set_is_nullable(false);
diff --git a/be/test/storage/segment/page_format_test.cpp
b/be/test/storage/segment/page_format_test.cpp
index b4e4a17ae6d..1b0087d53ba 100644
--- a/be/test/storage/segment/page_format_test.cpp
+++ b/be/test/storage/segment/page_format_test.cpp
@@ -33,6 +33,7 @@
#include <limits>
#include <map>
#include <memory>
+#include <numeric>
#include <set>
#include <string>
#include <string_view>
@@ -45,6 +46,7 @@
#include "core/assert_cast.h"
#include "core/column/column_complex.h"
#include "core/column/column_decimal.h"
+#include "core/column/column_dictionary.h"
#include "core/column/column_nullable.h"
#include "core/column/column_string.h"
#include "core/column/column_vector.h"
@@ -848,42 +850,30 @@ std::vector<std::string> storage_cells(FieldType type,
const IColumn& data) {
return cells;
}
-// Reads the column back the way a Segment reads it and checks that it holds
the rows written.
-Status verify_read_back(const CaseInput& input, const WrittenColumn& written,
- const std::string& path) {
- io::FileReaderSPtr file_reader;
- RETURN_IF_ERROR(io::global_local_filesystem()->open_file(path,
&file_reader));
- ColumnReaderOptions reader_options;
- reader_options.be_exec_version =
BeExecVersionManager::get_newest_version();
- std::shared_ptr<ColumnReader> reader;
- RETURN_IF_ERROR(ColumnReader::create(reader_options, written.meta,
written.meta.num_rows(),
- file_reader, &reader));
- ColumnIteratorUPtr iterator;
- RETURN_IF_ERROR(reader->new_iterator(&iterator, &input.column));
- OlapReaderStatistics stats;
- ColumnIteratorOptions iterator_options;
- iterator_options.stats = &stats;
- iterator_options.file_reader = file_reader.get();
- RETURN_IF_ERROR(iterator->init(iterator_options));
- RETURN_IF_ERROR(iterator->seek_to_ordinal(0));
- MutableColumnPtr read = input.data.column->clone_empty();
- size_t rows = written.meta.num_rows();
- bool has_null = false;
- RETURN_IF_ERROR(iterator->next_batch(&rows, read, &has_null));
- if (read->size() != input.rows()) {
- return Status::InternalError("read {} rows back, wrote {}",
read->size(), input.rows());
+// Checks that `read` holds the rows written at `rowids`.
+Status check_rows_read(const CaseInput& input, const WrittenColumn& written,
+ const std::vector<rowid_t>& rowids, const IColumn&
read) {
+ if (read.size() != rowids.size()) {
+ return Status::InternalError("read {} rows back, wanted {}",
read.size(), rowids.size());
}
-
if (input.column.is_nullable()) {
- const auto& read_null_map = assert_cast<const
ColumnNullable&>(*read).get_null_map_data();
+ const auto& read_null_map = assert_cast<const
ColumnNullable&>(read).get_null_map_data();
const auto& null_map =
assert_cast<const
ColumnNullable&>(*input.data.column).get_null_map_data();
- if (!std::equal(read_null_map.begin(), read_null_map.end(),
null_map.begin())) {
- return Status::InternalError("the NULL rows read back differ from
the ones written");
+ for (size_t i = 0; i < rowids.size(); ++i) {
+ if (read_null_map[i] != null_map[rowids[i]]) {
+ return Status::InternalError("row {} reads back as {}NULL",
rowids[i],
+ read_null_map[i] != 0 ? "" : "not
");
+ }
}
}
- auto expected = storage_cells(input.column.type(), *input.data.column);
- auto actual = storage_cells(input.column.type(), *read);
+ const auto written_cells = storage_cells(input.column.type(),
*input.data.column);
+ std::vector<std::string> expected;
+ expected.reserve(rowids.size());
+ for (const auto row : rowids) {
+ expected.push_back(written_cells[row]);
+ }
+ auto actual = storage_cells(input.column.type(), read);
// Reading turns a single-value bitmap into a one-value set, which is
written differently, so
// bitmaps are compared by value.
if
(check_and_get_column<ColumnBitmap>(*remove_nullable(input.data.column)) !=
nullptr) {
@@ -902,9 +892,9 @@ Status verify_read_back(const CaseInput& input, const
WrittenColumn& written,
written.meta.encoding() == PREFIX_ENCODING) {
const auto& null_map =
assert_cast<const
ColumnNullable&>(*input.data.column).get_null_map_data();
- for (size_t row = 0; row < expected.size(); ++row) {
- if (null_map[row] == 0) {
- expected[row].resize(input.column.length(), '\0');
+ for (size_t i = 0; i < rowids.size(); ++i) {
+ if (null_map[rowids[i]] == 0) {
+ expected[i].resize(input.column.length(), '\0');
}
}
}
@@ -919,12 +909,66 @@ Status verify_read_back(const CaseInput& input, const
WrittenColumn& written,
return text;
};
return Status::InternalError("row {} reads back as {} instead of {}",
- std::distance(actual.begin(),
actual_cell), hex(*actual_cell),
- hex(*expected_cell));
+ rowids[std::distance(actual.begin(),
actual_cell)],
+ hex(*actual_cell), hex(*expected_cell));
}
return Status::OK();
}
+// Reads the column back the way a Segment reads it, into columns like
`prototype`: every row by
+// batch, then two rows of every three by row id, so that the reads start and
stop inside NULL
+// runs. Checks that both hold the rows written.
+Status verify_read_back(const CaseInput& input, const WrittenColumn& written,
+ const std::string& path, const IColumn& prototype) {
+ io::FileReaderSPtr file_reader;
+ RETURN_IF_ERROR(io::global_local_filesystem()->open_file(path,
&file_reader));
+ ColumnReaderOptions reader_options;
+ reader_options.be_exec_version =
BeExecVersionManager::get_newest_version();
+ std::shared_ptr<ColumnReader> reader;
+ RETURN_IF_ERROR(ColumnReader::create(reader_options, written.meta,
written.meta.num_rows(),
+ file_reader, &reader));
+ ColumnIteratorUPtr iterator;
+ RETURN_IF_ERROR(reader->new_iterator(&iterator, &input.column));
+ OlapReaderStatistics stats;
+ ColumnIteratorOptions iterator_options;
+ iterator_options.stats = &stats;
+ iterator_options.file_reader = file_reader.get();
+ RETURN_IF_ERROR(iterator->init(iterator_options));
+ RETURN_IF_ERROR(iterator->seek_to_ordinal(0));
+ std::vector<rowid_t> rowids(input.rows());
+ std::iota(rowids.begin(), rowids.end(), rowid_t {0});
+ MutableColumnPtr read = prototype.clone_empty();
+ size_t rows = written.meta.num_rows();
+ bool has_null = false;
+ RETURN_IF_ERROR(iterator->next_batch(&rows, read, &has_null));
+ // A ColumnDictI32 holds codes: compare the strings they stand for.
+ read = read->convert_to_predicate_column_if_dictionary();
+ RETURN_IF_ERROR(check_rows_read(input, written, rowids, *read));
+
+ // BinaryPrefixPageDecoder does not read by row id.
+ if (written.meta.encoding() == PREFIX_ENCODING) {
+ return Status::OK();
+ }
+ std::erase_if(rowids, [](rowid_t row) { return row % 3 == 1; });
+ MutableColumnPtr picked = prototype.clone_empty();
+ // A ColumnDictI32 appends codes only into room reserved beforehand, as
SegmentIterator
+ // reserves the columns it reads into.
+ picked->reserve(rowids.size());
+ RETURN_IF_ERROR(iterator->read_by_rowids(rowids.data(), rowids.size(),
picked));
+ picked = picked->convert_to_predicate_column_if_dictionary();
+ return check_rows_read(input, written, rowids, *picked);
+}
+
+// The column a query that filters a string column reads it into, as
+// ReadSchema::get_predicate_column_ptr makes it.
+MutableColumnPtr dictionary_column(const CaseInput& input) {
+ MutableColumnPtr column = ColumnDictI32::create();
+ if (input.column.is_nullable()) {
+ column = ColumnNullable::create(std::move(column),
ColumnUInt8::create());
+ }
+ return column;
+}
+
// A page ends with its PageFooterPB, the footer length and the checksum.
uint32_t page_rows(const std::string& page) {
const size_t footer_size =
@@ -1143,8 +1187,16 @@ TEST_F(PageFormatTest,
RegisteredEncodingsKeepTheirPageBytes) {
EXPECT_TRUE(written.value().data_pages ==
rewritten.value().data_pages &&
written.value().dict_page ==
rewritten.value().dict_page)
<< "page bytes are not deterministic";
- const auto read_back = verify_read_back(input.value(),
written.value(), path);
+ const auto read_back = verify_read_back(input.value(),
written.value(), path,
+
*input.value().data.column);
EXPECT_TRUE(read_back.ok()) << read_back;
+ if (page_case.encoding == DICT_ENCODING) {
+ // The pages that fall back to plain encoding make the
dictionary page decoder
+ // replace the ColumnDictI32 it appends to with a ColumnString.
+ const auto dictionary_read_back = verify_read_back(
+ input.value(), written.value(), path,
*dictionary_column(input.value()));
+ EXPECT_TRUE(dictionary_read_back.ok()) << dictionary_read_back;
+ }
add_goldens(&goldens, page_case, written.value());
}
}
diff --git a/be/test/storage/segment/plain_page_test.cpp
b/be/test/storage/segment/plain_page_test.cpp
index 9c8ed90d9e8..f2975ccb617 100644
--- a/be/test/storage/segment/plain_page_test.cpp
+++ b/be/test/storage/segment/plain_page_test.cpp
@@ -22,10 +22,15 @@
#include <iostream>
#include "common/logging.h"
+#include "core/assert_cast.h"
+#include "core/column/column_vector.h"
#include "core/data_type/data_type_factory.hpp"
+#include "core/uint24.h"
+#include "core/value/vdatetime_value.h"
#include "storage/olap_common.h"
#include "storage/segment/page_builder.h"
#include "storage/segment/page_decoder.h"
+#include "storage/storage_layout.h"
#include "storage/types.h"
namespace doris {
@@ -154,6 +159,29 @@ public:
EXPECT_EQ(status.code(), ENTRY_NOT_FOUND);
}
}
+
+ // Eight consecutive days from 2020-01-01 in one plain page of V1 DATE
cells, each date
+ // stored as a uint24.
+ void build_date_v1_page(std::vector<VecDateTimeValue>* days, OwnedSlice*
page) {
+ using Layout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>;
+ constexpr size_t kRows = 8;
+ days->resize(kRows);
+ std::vector<uint24_t> cells(kRows);
+ for (size_t i = 0; i < kRows; ++i) {
+
ASSERT_TRUE((*days)[i].from_date_int64(static_cast<int64_t>(20200101 + i)));
+ cells[i] = Layout::to_storage((*days)[i]);
+ }
+ PageBuilderOptions options;
+ options.data_page_size = 256 * 1024;
+ PageBuilder* builder = nullptr;
+ ASSERT_TRUE(
+
PlainPageBuilder<FieldType::OLAP_FIELD_TYPE_DATE>::create(&builder,
options).ok());
+ std::unique_ptr<PageBuilder> page_builder(builder);
+ size_t added = kRows;
+ ASSERT_TRUE(page_builder->add(reinterpret_cast<const
uint8_t*>(cells.data()), &added).ok());
+ ASSERT_EQ(added, kRows);
+ ASSERT_TRUE(page_builder->finish(page).ok());
+ }
};
TEST_F(PlainPageTest, TestInt32PlainPageRandom) {
@@ -266,5 +294,45 @@ TEST_F(PlainPageTest, TestBoolPlainPageSeekValue) {
nullptr);
}
+// A V1 DATE page holds each date as a uint24 cell; a batch decodes the cells
into the dates
+// of a ColumnDate.
+TEST_F(PlainPageTest, TestDateV1PlainPageDecodesIntoDates) {
+ std::vector<VecDateTimeValue> days;
+ OwnedSlice page;
+ ASSERT_NO_FATAL_FAILURE(build_date_v1_page(&days, &page));
+ PageDecoderOptions decoder_options;
+ PlainPageDecoder<FieldType::OLAP_FIELD_TYPE_DATE> decoder(page.slice(),
decoder_options);
+ ASSERT_TRUE(decoder.init().ok());
+
+ MutableColumnPtr dates = ColumnDate::create();
+ size_t n = days.size();
+ ASSERT_TRUE(decoder.next_batch(&n, dates).ok());
+ ASSERT_EQ(n, days.size());
+ const auto& decoded = assert_cast<const ColumnDate&>(*dates).get_data();
+ for (size_t i = 0; i < days.size(); ++i) {
+ EXPECT_EQ(decoded[i], days[i]) << "row " << i;
+ }
+}
+
+// Rows read by id into a ColumnDate come back as their dates.
+TEST_F(PlainPageTest, TestDateV1PlainPageReadsRowIdsIntoDates) {
+ std::vector<VecDateTimeValue> days;
+ OwnedSlice page;
+ ASSERT_NO_FATAL_FAILURE(build_date_v1_page(&days, &page));
+ PageDecoderOptions decoder_options;
+ PlainPageDecoder<FieldType::OLAP_FIELD_TYPE_DATE> decoder(page.slice(),
decoder_options);
+ ASSERT_TRUE(decoder.init().ok());
+
+ const rowid_t rowids[] = {1, 3, 6};
+ MutableColumnPtr picked = ColumnDate::create();
+ size_t n = 3;
+ ASSERT_TRUE(decoder.read_by_rowids(rowids, 0, &n, picked).ok());
+ ASSERT_EQ(n, 3);
+ const auto& picked_dates = assert_cast<const
ColumnDate&>(*picked).get_data();
+ for (size_t i = 0; i < 3; ++i) {
+ EXPECT_EQ(picked_dates[i], days[rowids[i]]) << "row id " << rowids[i];
+ }
+}
+
} // namespace segment_v2
} // namespace doris
diff --git a/be/test/storage/storage_layout_test.cpp
b/be/test/storage/storage_layout_test.cpp
index 3e3583d5c1e..b2185ba26ae 100644
--- a/be/test/storage/storage_layout_test.cpp
+++ b/be/test/storage/storage_layout_test.cpp
@@ -46,8 +46,10 @@
namespace doris {
TEST(StorageLayoutTest, StorageValueSizeIsFieldTypeSize) {
-#define CHECK_SIZE(FT) \
- EXPECT_EQ(sizeof(CppTypeTraits<FieldType::FT>::CppType),
field_type_size(FieldType::FT)) << #FT;
+#define CHECK_SIZE(FT) \
+ EXPECT_EQ(sizeof(StorageTypeTraits<FieldType::FT>::StorageType), \
+ field_type_size(FieldType::FT)) \
+ << #FT;
CHECK_SIZE(OLAP_FIELD_TYPE_BOOL)
CHECK_SIZE(OLAP_FIELD_TYPE_TINYINT)
CHECK_SIZE(OLAP_FIELD_TYPE_SMALLINT)
@@ -214,7 +216,7 @@ TEST(StorageLayoutTest, ColumnToStoragePreservesSource) {
dates->insert_value(day);
dates->insert_value(day);
using DateLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>;
- using StoredDate = CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
+ using StoredDate =
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::StorageType;
StorageBuffers date_buffers;
const auto* date_out = DateLayout::column_to_storage(*dates, 0, 2,
date_buffers);
for (size_t i = 0; i < 2; ++i) {
@@ -228,7 +230,7 @@ namespace {
template <FieldType FT>
void expect_floating_point_range_views() {
- using Value = typename CppTypeTraits<FT>::CppType;
+ using Value = typename StorageTypeTraits<FT>::StorageType;
using UInt = std::conditional_t<sizeof(Value) == sizeof(uint32_t),
uint32_t, uint64_t>;
using Column =
typename
PrimitiveTypeTraits<storage_field_type_to_primitive_type(FT)>::ColumnType;
@@ -393,7 +395,7 @@ TEST(StorageLayoutTest,
RuntimeTypeConvertsThroughItsLayout) {
VecDateTimeValue day;
ASSERT_TRUE(day.from_date_int64(20200101));
dates->insert_value(day);
- using StoredDate = CppTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::CppType;
+ using StoredDate =
StorageTypeTraits<FieldType::OLAP_FIELD_TYPE_DATE>::StorageType;
StoredDate stored;
memcpy(&stored, column_to_storage(FieldType::OLAP_FIELD_TYPE_DATE, *dates,
0, 1, buffers),
sizeof(stored));
@@ -409,6 +411,110 @@ TEST(StorageLayoutTest,
RuntimeTypeConvertsThroughItsLayout) {
Exception);
}
+TEST(StorageLayoutTest, ToPrimitiveInvertsToStorage) {
+ using DateLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>;
+ VecDateTimeValue day;
+ ASSERT_TRUE(day.from_date_int64(20200229));
+ const VecDateTimeValue read_day =
DateLayout::to_primitive(DateLayout::to_storage(day));
+ EXPECT_EQ(read_day, day);
+ EXPECT_EQ(read_day.to_olap_date(), day.to_olap_date());
+ VecDateTimeValue last_day;
+ ASSERT_TRUE(last_day.from_date_int64(99991231));
+ EXPECT_EQ(DateLayout::to_primitive(DateLayout::to_storage(last_day)),
last_day);
+
+ using DateTimeLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME>;
+ VecDateTimeValue moment;
+ ASSERT_TRUE(moment.from_date_int64(20200101123045));
+
EXPECT_EQ(DateTimeLayout::to_primitive(DateTimeLayout::to_storage(moment)),
moment);
+
+ using DecimalLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL>;
+ const DecimalV2Value amount(123, 456000000);
+ EXPECT_EQ(DecimalLayout::to_primitive(DecimalLayout::to_storage(amount)),
amount);
+ const DecimalV2Value debt(-123, -456000000);
+ EXPECT_EQ(DecimalLayout::to_primitive(DecimalLayout::to_storage(debt)),
debt);
+ const DecimalV2Value read_debt =
+ DecimalLayout::to_primitive(decimal12_t {.integer = -123,
.fraction = -456000000});
+ EXPECT_EQ(read_debt.int_value(), -123);
+ EXPECT_EQ(read_debt.frac_value(), -456000000);
+
+ // Reading does not canonicalise: a stored NaN keeps its payload.
+ using FloatLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_FLOAT>;
+ const auto payload_nan = std::bit_cast<float>(0x7FC12345U);
+ EXPECT_EQ(std::bit_cast<uint32_t>(FloatLayout::to_primitive(payload_nan)),
0x7FC12345U);
+ EXPECT_EQ(FloatLayout::to_primitive(FloatLayout::to_storage(1.5F)), 1.5F);
+
+ DateV2Value<DateV2ValueType> date;
+ ASSERT_TRUE(date.from_date_int64(20200101));
+ EXPECT_EQ(
+
StorageLayout<FieldType::OLAP_FIELD_TYPE_DATEV2>::to_primitive(date.to_date_int_val()),
+ date);
+
EXPECT_EQ(StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL32>::to_primitive(-12345),
+ Decimal32(-12345));
+
EXPECT_EQ(StorageLayout<FieldType::OLAP_FIELD_TYPE_BOOL>::to_primitive(uint8_t(1)),
UInt8(1));
+}
+
+TEST(StorageLayoutTest, StorageToColumnRepacksTheV1LayoutsFromUnalignedBytes) {
+ using DateLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATE>;
+ using DateTimeLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DATETIME>;
+ using DecimalLayout = StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL>;
+
+ VecDateTimeValue day1;
+ VecDateTimeValue day2;
+ ASSERT_TRUE(day1.from_date_int64(20200101));
+ ASSERT_TRUE(day2.from_date_int64(20211231));
+ VecDateTimeValue moment;
+ ASSERT_TRUE(moment.from_date_int64(20200101123045));
+ const DecimalV2Value amount(-123, -456000000);
+
+ // A page holds the stored values after a header, so they are not aligned.
+ std::string page(1, 'h');
+ auto put = [&](const auto& value) {
+ page.append(reinterpret_cast<const char*>(&value), sizeof(value));
+ };
+ put(DateLayout::to_storage(day1));
+ put(DateLayout::to_storage(day2));
+ put(DateTimeLayout::to_storage(moment));
+ put(DecimalLayout::to_storage(amount));
+ const auto* stored = reinterpret_cast<const uint8_t*>(page.data()) + 1;
+
+ auto dates = ColumnDate::create();
+ dates->insert_value(day2);
+ DateLayout::storage_to_column(stored, 2, *dates);
+ ASSERT_EQ(dates->size(), 3);
+ EXPECT_EQ(dates->get_data()[1], day1);
+ EXPECT_EQ(dates->get_data()[2], day2);
+ stored += 2 * sizeof(uint24_t);
+
+ auto moments = ColumnDateTime::create();
+ DateTimeLayout::storage_to_column(stored, 1, *moments);
+ ASSERT_EQ(moments->size(), 1);
+ EXPECT_EQ(moments->get_data()[0], moment);
+ stored += sizeof(int64_t);
+
+ auto amounts = ColumnDecimal128V2::create(0, 9);
+ DecimalLayout::storage_to_column(stored, 1, *amounts);
+ ASSERT_EQ(amounts->size(), 1);
+ EXPECT_EQ(amounts->get_data()[0], amount);
+}
+
+TEST(StorageLayoutTest, StorageToColumnCopiesStoredValuesAsTheyAre) {
+ const float stored_floats[] = {1.5F, std::bit_cast<float>(0x7FC12345U)};
+ auto floats = ColumnFloat32::create();
+ StorageLayout<FieldType::OLAP_FIELD_TYPE_FLOAT>::storage_to_column(
+ reinterpret_cast<const uint8_t*>(stored_floats), 2, *floats);
+ ASSERT_EQ(floats->size(), 2);
+ EXPECT_EQ(floats->get_data()[0], 1.5F);
+ EXPECT_EQ(std::bit_cast<uint32_t>(floats->get_data()[1]), 0x7FC12345U);
+
+ const int32_t stored_decimals[] = {-12345, 67890};
+ auto decimals = ColumnDecimal32::create(0, 3);
+ StorageLayout<FieldType::OLAP_FIELD_TYPE_DECIMAL32>::storage_to_column(
+ reinterpret_cast<const uint8_t*>(stored_decimals), 2, *decimals);
+ ASSERT_EQ(decimals->size(), 2);
+ EXPECT_EQ(decimals->get_data()[0], Decimal32(-12345));
+ EXPECT_EQ(decimals->get_data()[1], Decimal32(67890));
+}
+
TEST(StorageLayoutTest, ObjectBatchSerialisesEveryValue) {
auto bitmaps = ColumnBitmap::create();
for (size_t i = 0; i < 3; ++i) {
diff --git a/be/test/core/block/column_vector_test.cpp
b/be/test/storage/storage_layout_test_util.h
similarity index 59%
rename from be/test/core/block/column_vector_test.cpp
rename to be/test/storage/storage_layout_test_util.h
index f1d233f6115..32bb4c4493e 100644
--- a/be/test/core/block/column_vector_test.cpp
+++ b/be/test/storage/storage_layout_test_util.h
@@ -1,4 +1,3 @@
-
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
@@ -16,26 +15,23 @@
// specific language governing permissions and limitations
// under the License.
-#include "core/column/column_vector.h"
-
-#include <gtest/gtest-message.h>
-#include <gtest/gtest-test-part.h>
+#pragma once
-#include <string>
-
-#include "gtest/gtest_pred_impl.h"
+#include "core/data_type/primitive_type.h"
+#include "core/data_type/storage_field_type.h"
+#include "core/field.h"
+#include "storage/storage_layout.h"
namespace doris {
-TEST(VColumnVectorTest, insert_date_column) {
- auto column = ColumnInt64::create();
-
- size_t rows = 4096;
- int64_t val = 0;
- for (size_t i = 0; i < rows; ++i) {
- column->insert_date_column(reinterpret_cast<char*>(&val), 1);
- }
- ASSERT_EQ(column->size(), rows);
+// The Field a stored cell of PT's FieldType reads back as, for tests that
state their
+// expectations in stored bytes.
+template <PrimitiveType PT>
+Field field_of_cell(
+ const typename
StorageLayout<primitive_type_to_storage_field_type(PT)>::StorageValue&
+ value) {
+ return Field::create_field<PT>(
+
StorageLayout<primitive_type_to_storage_field_type(PT)>::to_primitive(value));
}
} // namespace doris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]