This is an automated email from the ASF dual-hosted git repository.

yiguolei 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 2f760a8fe17 [refactor](be) Use concrete columns for VariantV2 encoded 
storage (#66427)
2f760a8fe17 is described below

commit 2f760a8fe17fa7bc124df5ed11e1b4e5f03abcd9
Author: Mryange <[email protected]>
AuthorDate: Mon Aug 10 16:49:05 2026 +0800

    [refactor](be) Use concrete columns for VariantV2 encoded storage (#66427)
    
    ### What problem does this PR solve?
    
    
    Problem Summary: ColumnVariantV2 stored its fixed encoded metadata,
    metadata-id, and value columns through IColumn pointers. This obscured
    their invariant types and required repeated runtime casts throughout
    encoded-state operations. Store these subcolumns through their concrete
    COW pointer types, update the read view and SerDe boundaries
    accordingly, and keep checked conversions only at generic IColumn
    interface boundaries.
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 .../core/column/variant_v2/column_variant_v2.cpp   | 185 ++++++++++-----------
 be/src/core/column/variant_v2/column_variant_v2.h  |  24 ++-
 .../variant_v2/column_variant_v2_read_view.cpp     |  24 +--
 .../data_type_serde/data_type_variant_v2_serde.cpp |   9 +-
 be/test/core/column/column_variant_v2_test.cpp     |   8 +-
 5 files changed, 122 insertions(+), 128 deletions(-)

diff --git a/be/src/core/column/variant_v2/column_variant_v2.cpp 
b/be/src/core/column/variant_v2/column_variant_v2.cpp
index 6a74ac091ee..6b37eb64792 100644
--- a/be/src/core/column/variant_v2/column_variant_v2.cpp
+++ b/be/src/core/column/variant_v2/column_variant_v2.cpp
@@ -46,7 +46,7 @@
 namespace doris {
 namespace {
 
-using MetaIdsColumn = ColumnVector<TYPE_UINT32>;
+using MetaIdsColumn = ColumnVariantV2::MetadataIdsColumn;
 constexpr uint32_t UNMAPPED_METADATA_ID = std::numeric_limits<uint32_t>::max();
 constexpr std::array<char, 3> EMPTY_OBJECT_VALUE {static_cast<char>(0x02), 0, 
0};
 
@@ -107,12 +107,17 @@ void validate_offsets(StringRef bytes, std::span<const 
uint32_t> offsets,
     }
 }
 
-void require_exclusive(const IColumn::WrappedPtr& column, std::string_view 
description) {
-    const auto& immutable = static_cast<const IColumn::Ptr&>(column);
-    DORIS_CHECK(immutable->is_exclusive())
+template <typename WrappedPtr>
+void require_exclusive(const WrappedPtr& column, std::string_view description) 
{
+    DORIS_CHECK(column->is_exclusive())
             << "ColumnVariantV2 " << description << " must be COW-detached 
before mutation";
 }
 
+template <typename ColumnType, typename ColumnPtrType>
+typename ColumnType::Ptr cast_column_ptr(ColumnPtrType column) {
+    return ColumnType::cast_to_column_ptr(assert_cast<const 
ColumnType*>(column.get()));
+}
+
 void reserve_rows(ColumnString& values, MetaIdsColumn& metadata_ids, size_t 
value_bytes,
                   size_t rows) {
     const size_t final_value_bytes = values.get_chars().size() + value_bytes;
@@ -316,22 +321,16 @@ ValidatedTypedInput validate_typed_input(ColumnPtr 
column, DataTypePtr scalar_ty
 } // namespace
 
 #ifdef BE_TEST
-void ColumnVariantV2::TestAccess::replace_encoded_subcolumn(ColumnVariantV2& 
column, size_t index,
-                                                            ColumnPtr 
replacement) {
+void ColumnVariantV2::TestAccess::replace_metadata_ids(ColumnVariantV2& column,
+                                                       MetadataIdsColumn::Ptr 
replacement) {
     DORIS_CHECK(!column._typed);
-    switch (index) {
-    case 0:
-        static_cast<IColumn::Ptr&>(column._metadatas) = std::move(replacement);
-        break;
-    case 1:
-        static_cast<IColumn::Ptr&>(column._meta_ids) = std::move(replacement);
-        break;
-    case 2:
-        static_cast<IColumn::Ptr&>(column._values) = std::move(replacement);
-        break;
-    default:
-        DORIS_CHECK(false) << "ColumnVariantV2 test subcolumn index is out of 
range";
-    }
+    static_cast<MetadataIdsColumn::Ptr&>(column._meta_ids) = 
std::move(replacement);
+}
+
+void ColumnVariantV2::TestAccess::replace_values(ColumnVariantV2& column,
+                                                 ColumnString::Ptr 
replacement) {
+    DORIS_CHECK(!column._typed);
+    static_cast<ColumnString::Ptr&>(column._values) = std::move(replacement);
 }
 #endif
 
@@ -385,9 +384,9 @@ void ColumnVariantV2::ensure_encoded() {
                                       encoded = 
encode_typed_column<Type>(nullable, column, scale);
                                   });
 
-    static_cast<IColumn::Ptr&>(_metadatas) = std::move(encoded.metadatas);
-    static_cast<IColumn::Ptr&>(_meta_ids) = std::move(encoded.metadata_ids);
-    static_cast<IColumn::Ptr&>(_values) = std::move(encoded.values);
+    static_cast<ColumnString::Ptr&>(_metadatas) = std::move(encoded.metadatas);
+    static_cast<MetadataIdsColumn::Ptr&>(_meta_ids) = 
std::move(encoded.metadata_ids);
+    static_cast<ColumnString::Ptr&>(_values) = std::move(encoded.values);
     static_cast<IColumn::Ptr&>(_typed).reset();
     _typed_type.reset();
     _check_invariants();
@@ -469,9 +468,9 @@ void ColumnVariantV2::sanity_check() const {
     }
     _check_invariants();
     if (!_typed) {
-        const auto& metadatas = assert_cast<const ColumnString&>(*_metadatas);
-        const auto& metadata_ids = assert_cast<const 
MetaIdsColumn&>(*_meta_ids).get_data();
-        const auto& values = assert_cast<const ColumnString&>(*_values);
+        const auto& metadatas = *_metadatas;
+        const auto& metadata_ids = _meta_ids->get_data();
+        const auto& values = *_values;
         for (size_t id = 0; id < metadatas.size(); ++id) {
             const StringRef metadata = metadatas.get_data_at(id);
             validate_variant_metadata({metadata.data, metadata.size});
@@ -490,9 +489,9 @@ void ColumnVariantV2::for_each_subcolumn(ColumnCallback 
callback) const {
     if (_typed) {
         callback(*static_cast<const IColumn::Ptr&>(_typed));
     } else {
-        callback(*static_cast<const IColumn::Ptr&>(_metadatas));
-        callback(*static_cast<const IColumn::Ptr&>(_meta_ids));
-        callback(*static_cast<const IColumn::Ptr&>(_values));
+        callback(*_metadatas);
+        callback(*_meta_ids);
+        callback(*_values);
     }
 }
 
@@ -500,9 +499,9 @@ void ColumnVariantV2::mutate_subcolumns() {
     if (_typed) {
         mutate_subcolumn(_typed);
     } else {
-        mutate_subcolumn(_metadatas);
-        mutate_subcolumn(_meta_ids);
-        mutate_subcolumn(_values);
+        mutate_subcolumn<ColumnString>(_metadatas);
+        mutate_subcolumn<MetadataIdsColumn>(_meta_ids);
+        mutate_subcolumn<ColumnString>(_values);
     }
 }
 
@@ -511,7 +510,7 @@ void ColumnVariantV2::clear() {
         mutate_subcolumn(_typed);
         _typed->clear();
     } else {
-        auto& metadata_ptr = static_cast<IColumn::Ptr&>(_metadatas);
+        auto& metadata_ptr = static_cast<ColumnString::Ptr&>(_metadatas);
         if (metadata_ptr->is_exclusive()) {
             _metadatas->clear();
         } else {
@@ -563,8 +562,8 @@ void ColumnVariantV2::insert_encoded_rows( // 
NOLINT(readability-function-size)
 
     require_exclusive(_meta_ids, "metadata ids");
     require_exclusive(_values, "values");
-    auto& values = assert_cast<ColumnString&>(*_values);
-    auto& metadata_ids = assert_cast<MetaIdsColumn&>(*_meta_ids);
+    auto& values = *_values;
+    auto& metadata_ids = *_meta_ids;
     reserve_rows(values, metadata_ids, data.value_bytes.size, rows);
 
     if (data.meta_ids.empty()) {
@@ -626,8 +625,8 @@ void ColumnVariantV2::insert_encoded_batch(const 
VariantBatchBuilder& block) {
 
     require_exclusive(_meta_ids, "metadata ids");
     require_exclusive(_values, "values");
-    auto& values = assert_cast<ColumnString&>(*_values);
-    auto& metadata_ids = assert_cast<MetaIdsColumn&>(*_meta_ids);
+    auto& values = *_values;
+    auto& metadata_ids = *_meta_ids;
     reserve_rows(values, metadata_ids, value_bytes.size, rows);
 
     const uint32_t id = _find_or_insert_metadata({metadata.data, 
metadata.size});
@@ -642,12 +641,11 @@ VariantRef ColumnVariantV2::get_value_ref(size_t row) 
const {
     DCHECK(!_typed);
     DCHECK(_typed_type == nullptr);
     DCHECK_LT(row, size());
-    const auto& metadata_ids = assert_cast<const 
MetaIdsColumn&>(*_meta_ids).get_data();
+    const auto& metadata_ids = _meta_ids->get_data();
     const uint32_t metadata_id = metadata_ids[row];
     DCHECK_LT(metadata_id, _metadatas->size());
-    const StringRef metadata =
-            assert_cast<const 
ColumnString&>(*_metadatas).get_data_at(metadata_id);
-    const StringRef value = assert_cast<const 
ColumnString&>(*_values).get_data_at(row);
+    const StringRef metadata = _metadatas->get_data_at(metadata_id);
+    const StringRef value = _values->get_data_at(row);
     return {.metadata = {.data = metadata.data, .size = metadata.size}, .value 
= value};
 }
 
@@ -686,8 +684,8 @@ void ColumnVariantV2::insert_many_defaults(size_t length) {
     require_exclusive(_values, "values");
 
     const size_t value_bytes = length * EMPTY_OBJECT_VALUE.size();
-    auto& values = assert_cast<ColumnString&>(*_values);
-    auto& metadata_ids = assert_cast<MetaIdsColumn&>(*_meta_ids);
+    auto& values = *_values;
+    auto& metadata_ids = *_meta_ids;
     DORIS_CHECK_LE(value_bytes, std::numeric_limits<size_t>::max() - 
values.get_chars().size())
             << "default value bytes overflow the destination";
     reserve_rows(values, metadata_ids, value_bytes, length);
@@ -756,30 +754,29 @@ void ColumnVariantV2::insert_range_from( // 
NOLINT(readability-function-size)
 
     require_exclusive(_meta_ids, "metadata ids");
     require_exclusive(_values, "values");
-    const auto& source_metadatas = assert_cast<const 
ColumnString&>(*source._metadatas);
-    const auto& source_metadata_ids =
-            assert_cast<const MetaIdsColumn&>(*source._meta_ids).get_data();
-
-    const auto& source_values = assert_cast<const 
ColumnString&>(*source._values);
+    const auto& source_metadatas = *source._metadatas;
+    const auto& source_metadata_ids = source._meta_ids->get_data();
+    const auto& source_values = *source._values;
     const auto& source_offsets = source_values.get_offsets();
     const size_t value_begin = source_offsets[static_cast<ssize_t>(start) - 1];
     const size_t value_end = source_offsets[start + length - 1];
-    const bool destination_has_no_metadata = static_cast<const 
IColumn::Ptr&>(_metadatas)->empty();
+    const bool destination_has_no_metadata =
+            static_cast<const ColumnString::Ptr&>(_metadatas)->empty();
     const bool adopt_metadata = empty() && destination_has_no_metadata;
-    const bool already_shared = static_cast<const 
IColumn::Ptr&>(_metadatas).get() ==
-                                static_cast<const 
IColumn::Ptr&>(source._metadatas).get();
+    const bool already_shared =
+            static_cast<const ColumnString::Ptr&>(_metadatas).get() == 
source._metadatas.get();
     DorisVector<uint32_t> remap;
     if (!adopt_metadata && !already_shared) {
         remap.assign(source_metadatas.size(), UNMAPPED_METADATA_ID);
     }
-    auto& values = assert_cast<ColumnString&>(*_values);
-    auto& metadata_ids = assert_cast<MetaIdsColumn&>(*_meta_ids);
+    auto& values = *_values;
+    auto& metadata_ids = *_meta_ids;
     reserve_rows(values, metadata_ids, value_end - value_begin, length);
     if (adopt_metadata) {
         _metadatas = source._metadatas;
     }
-    const bool shared_metadata = static_cast<const 
IColumn::Ptr&>(_metadatas).get() ==
-                                 static_cast<const 
IColumn::Ptr&>(source._metadatas).get();
+    const bool shared_metadata =
+            static_cast<const ColumnString::Ptr&>(_metadatas).get() == 
source._metadatas.get();
     values.insert_range_from(source_values, start, length);
     if (shared_metadata) {
         metadata_ids.insert_range_from(*source._meta_ids, start, length);
@@ -840,27 +837,27 @@ void ColumnVariantV2::insert_indices_from( // 
NOLINT(readability-function-size)
 
     require_exclusive(_meta_ids, "metadata ids");
     require_exclusive(_values, "values");
-    const auto& source_metadatas = assert_cast<const 
ColumnString&>(*source._metadatas);
-    const auto& source_metadata_ids =
-            assert_cast<const MetaIdsColumn&>(*source._meta_ids).get_data();
-    const auto& source_values = assert_cast<const 
ColumnString&>(*source._values);
+    const auto& source_metadatas = *source._metadatas;
+    const auto& source_metadata_ids = source._meta_ids->get_data();
+    const auto& source_values = *source._values;
 
-    const bool destination_has_no_metadata = static_cast<const 
IColumn::Ptr&>(_metadatas)->empty();
+    const bool destination_has_no_metadata =
+            static_cast<const ColumnString::Ptr&>(_metadatas)->empty();
     const bool adopt_metadata = empty() && destination_has_no_metadata;
-    const bool already_shared = static_cast<const 
IColumn::Ptr&>(_metadatas).get() ==
-                                static_cast<const 
IColumn::Ptr&>(source._metadatas).get();
+    const bool already_shared =
+            static_cast<const ColumnString::Ptr&>(_metadatas).get() == 
source._metadatas.get();
     DorisVector<uint32_t> remap;
     if (!adopt_metadata && !already_shared) {
         remap.assign(source_metadatas.size(), UNMAPPED_METADATA_ID);
     }
-    auto& values = assert_cast<ColumnString&>(*_values);
-    auto& metadata_ids = assert_cast<MetaIdsColumn&>(*_meta_ids);
+    auto& values = *_values;
+    auto& metadata_ids = *_meta_ids;
     metadata_ids.get_data().reserve(metadata_ids.size() + rows);
     if (adopt_metadata) {
         _metadatas = source._metadatas;
     }
-    const bool shared_metadata = static_cast<const 
IColumn::Ptr&>(_metadatas).get() ==
-                                 static_cast<const 
IColumn::Ptr&>(source._metadatas).get();
+    const bool shared_metadata =
+            static_cast<const ColumnString::Ptr&>(_metadatas).get() == 
source._metadatas.get();
     values.insert_indices_from(source_values, indices_begin, indices_end);
     if (shared_metadata) {
         metadata_ids.insert_indices_from(*source._meta_ids, indices_begin, 
indices_end);
@@ -1184,17 +1181,18 @@ ColumnPtr ColumnVariantV2::filter(const Filter& filter, 
ssize_t result_size_hint
         result->_check_invariants();
         return result;
     }
-    ColumnPtr filtered_values =
-            static_cast<const IColumn::Ptr&>(_values)->filter(filter, 
result_size_hint);
-    ColumnPtr filtered_metadata_ids =
-            static_cast<const IColumn::Ptr&>(_meta_ids)->filter(filter, 
result_size_hint);
+    ColumnPtr filtered_values = _values->filter(filter, result_size_hint);
+    ColumnPtr filtered_metadata_ids = _meta_ids->filter(filter, 
result_size_hint);
     DORIS_CHECK_EQ(filtered_values->size(), filtered_metadata_ids->size())
             << "filtered encoded row counts differ";
 
     auto result = ColumnVariantV2::create();
-    static_cast<IColumn::Ptr&>(result->_metadatas) = static_cast<const 
IColumn::Ptr&>(_metadatas);
-    static_cast<IColumn::Ptr&>(result->_meta_ids) = 
std::move(filtered_metadata_ids);
-    static_cast<IColumn::Ptr&>(result->_values) = std::move(filtered_values);
+    static_cast<ColumnString::Ptr&>(result->_metadatas) =
+            static_cast<const ColumnString::Ptr&>(_metadatas);
+    static_cast<MetadataIdsColumn::Ptr&>(result->_meta_ids) =
+            
cast_column_ptr<MetadataIdsColumn>(std::move(filtered_metadata_ids));
+    static_cast<ColumnString::Ptr&>(result->_values) =
+            cast_column_ptr<ColumnString>(std::move(filtered_values));
     result->_check_invariants();
     return result;
 }
@@ -1241,17 +1239,18 @@ MutableColumnPtr ColumnVariantV2::permute(const 
Permutation& permutation, size_t
         return result;
     }
 
-    MutableColumnPtr permuted_values =
-            static_cast<const IColumn::Ptr&>(_values)->permute(permutation, 
result_size);
-    MutableColumnPtr permuted_metadata_ids =
-            static_cast<const IColumn::Ptr&>(_meta_ids)->permute(permutation, 
result_size);
+    MutableColumnPtr permuted_values = _values->permute(permutation, 
result_size);
+    MutableColumnPtr permuted_metadata_ids = _meta_ids->permute(permutation, 
result_size);
     DORIS_CHECK_EQ(permuted_values->size(), permuted_metadata_ids->size())
             << "permuted encoded row counts differ";
 
     auto result = ColumnVariantV2::create();
-    static_cast<IColumn::Ptr&>(result->_metadatas) = static_cast<const 
IColumn::Ptr&>(_metadatas);
-    static_cast<IColumn::Ptr&>(result->_meta_ids) = 
std::move(permuted_metadata_ids);
-    static_cast<IColumn::Ptr&>(result->_values) = std::move(permuted_values);
+    static_cast<ColumnString::Ptr&>(result->_metadatas) =
+            static_cast<const ColumnString::Ptr&>(_metadatas);
+    static_cast<MetadataIdsColumn::Ptr&>(result->_meta_ids) =
+            
cast_column_ptr<MetadataIdsColumn>(std::move(permuted_metadata_ids));
+    static_cast<ColumnString::Ptr&>(result->_values) =
+            cast_column_ptr<ColumnString>(std::move(permuted_values));
     result->_check_invariants();
     return result;
 }
@@ -1278,14 +1277,15 @@ MutableColumnPtr ColumnVariantV2::clone_resized(size_t 
new_size) const {
     }
 
     const size_t copied_rows = std::min(size(), new_size);
-    MutableColumnPtr copied_values =
-            static_cast<const 
IColumn::Ptr&>(_values)->clone_resized(copied_rows);
-    MutableColumnPtr copied_metadata_ids =
-            static_cast<const 
IColumn::Ptr&>(_meta_ids)->clone_resized(copied_rows);
+    MutableColumnPtr copied_values = _values->clone_resized(copied_rows);
+    MutableColumnPtr copied_metadata_ids = 
_meta_ids->clone_resized(copied_rows);
     auto result = ColumnVariantV2::create();
-    static_cast<IColumn::Ptr&>(result->_metadatas) = static_cast<const 
IColumn::Ptr&>(_metadatas);
-    static_cast<IColumn::Ptr&>(result->_meta_ids) = 
std::move(copied_metadata_ids);
-    static_cast<IColumn::Ptr&>(result->_values) = std::move(copied_values);
+    static_cast<ColumnString::Ptr&>(result->_metadatas) =
+            static_cast<const ColumnString::Ptr&>(_metadatas);
+    static_cast<MetadataIdsColumn::Ptr&>(result->_meta_ids) =
+            cast_column_ptr<MetadataIdsColumn>(std::move(copied_metadata_ids));
+    static_cast<ColumnString::Ptr&>(result->_values) =
+            cast_column_ptr<ColumnString>(std::move(copied_values));
     if (new_size > copied_rows) {
         result->insert_many_defaults(new_size - copied_rows);
     }
@@ -1327,8 +1327,7 @@ void ColumnVariantV2::replace_column_data(const IColumn&, 
size_t, size_t) {
 uint32_t ColumnVariantV2::_find_or_insert_metadata(StringRef metadata) {
     DORIS_CHECK(metadata.data != nullptr || metadata.size == 0)
             << "metadata bytes have a null pointer";
-    const auto& current_metadatas =
-            assert_cast<const ColumnString&>(*static_cast<const 
IColumn::Ptr&>(_metadatas));
+    const auto& current_metadatas = *static_cast<const 
ColumnString::Ptr&>(_metadatas);
     for (uint32_t id = 0; id < current_metadatas.size(); ++id) {
         if (current_metadatas.get_data_at(id) == metadata) {
             return id;
@@ -1340,7 +1339,7 @@ uint32_t 
ColumnVariantV2::_find_or_insert_metadata(StringRef metadata) {
     }
 
     _detach_metadata_for_write();
-    auto& metadatas = assert_cast<ColumnString&>(*_metadatas);
+    auto& metadatas = *_metadatas;
     const size_t new_chars_size = metadatas.get_chars().size() + metadata.size;
     ColumnString::check_chars_length(new_chars_size, metadatas.size() + 1, 
_meta_ids->size());
     metadatas.get_chars().reserve(new_chars_size);
@@ -1361,9 +1360,9 @@ void ColumnVariantV2::_adopt_state_from(ColumnVariantV2& 
replacement) {
 }
 
 void ColumnVariantV2::_detach_metadata_for_write() {
-    auto& metadata_ptr = static_cast<IColumn::Ptr&>(_metadatas);
+    auto& metadata_ptr = static_cast<ColumnString::Ptr&>(_metadatas);
     if (!metadata_ptr->is_exclusive()) {
-        metadata_ptr = std::move(*metadata_ptr).mutate();
+        metadata_ptr = 
cast_column_ptr<ColumnString>(std::move(*metadata_ptr).mutate());
     }
 }
 
@@ -1383,8 +1382,8 @@ void ColumnVariantV2::_check_invariants() const {
     }
 
     DORIS_CHECK(_typed_type == nullptr) << "encoded state cannot retain a 
typed data type";
-    const auto& metadata_ids = assert_cast<const 
MetaIdsColumn&>(*_meta_ids).get_data();
-    const auto& values = assert_cast<const ColumnString&>(*_values);
+    const auto& metadata_ids = _meta_ids->get_data();
+    const auto& values = *_values;
     DORIS_CHECK_EQ(metadata_ids.size(), values.size())
             << "ColumnVariantV2 encoded row counts differ";
 }
diff --git a/be/src/core/column/variant_v2/column_variant_v2.h 
b/be/src/core/column/variant_v2/column_variant_v2.h
index e39bef34547..4bf2ae4470d 100644
--- a/be/src/core/column/variant_v2/column_variant_v2.h
+++ b/be/src/core/column/variant_v2/column_variant_v2.h
@@ -26,6 +26,8 @@
 #include "core/assert_cast.h"
 #include "core/column/column.h"
 #include "core/column/column_const.h"
+#include "core/column/column_string.h"
+#include "core/column/column_vector.h"
 #include "core/column/variant_v2/column_variant_v2_typed_column.h"
 #include "core/custom_allocator.h"
 #include "core/data_type/data_type.h"
@@ -41,6 +43,8 @@ class VariantBatchBuilder;
 // typed scalar column. Mixed operations materialize the typed state as 
encoded bytes on demand.
 class ColumnVariantV2 final : public COWHelper<IColumn, ColumnVariantV2> {
 public:
+    using MetadataIdsColumn = ColumnVector<TYPE_UINT32>;
+
     struct EncodedDataView {
         StringRef metadata_bytes;
         std::span<const uint32_t> metadata_offsets;
@@ -65,13 +69,14 @@ public:
 
     private:
         friend class ColumnVariantV2;
-        ReadView(const IColumn* metadatas, const IColumn* metadata_ids, const 
IColumn* values);
+        ReadView(const ColumnString* metadatas, const MetadataIdsColumn* 
metadata_ids,
+                 const ColumnString* values);
         ReadView(const IColumn* typed, const DataTypePtr* typed_type);
 
         bool _typed_state = false;
-        const IColumn* _metadatas = nullptr;
-        const IColumn* _metadata_ids = nullptr;
-        const IColumn* _values = nullptr;
+        const ColumnString* _metadatas = nullptr;
+        const MetadataIdsColumn* _metadata_ids = nullptr;
+        const ColumnString* _values = nullptr;
         const IColumn* _typed = nullptr;
         const DataTypePtr* _typed_type = nullptr;
     };
@@ -79,8 +84,9 @@ public:
 #ifdef BE_TEST
     // Narrow unit-test seam for encoded-state invariant coverage.
     struct TestAccess {
-        static void replace_encoded_subcolumn(ColumnVariantV2& column, size_t 
index,
-                                              ColumnPtr replacement);
+        static void replace_metadata_ids(ColumnVariantV2& column,
+                                         MetadataIdsColumn::Ptr replacement);
+        static void replace_values(ColumnVariantV2& column, ColumnString::Ptr 
replacement);
     };
 #endif
 
@@ -189,9 +195,9 @@ private:
     // uint32 id costs four bytes per encoded row, but avoids repeating 
object-key metadata and
     // gives canonical comparison, hashing, subpath lookup, and binary SerDe 
O(1) schema access.
     // It is required because valid external Variant rows may use different 
metadata dictionaries.
-    IColumn::WrappedPtr _metadatas;
-    IColumn::WrappedPtr _meta_ids;
-    IColumn::WrappedPtr _values;
+    ColumnString::WrappedPtr _metadatas;
+    MetadataIdsColumn::WrappedPtr _meta_ids;
+    ColumnString::WrappedPtr _values;
 
     // A non-null _typed always means all encoded buffers are empty and the 
entire column has the
     // single type described by _typed_type.
diff --git a/be/src/core/column/variant_v2/column_variant_v2_read_view.cpp 
b/be/src/core/column/variant_v2/column_variant_v2_read_view.cpp
index 3ce60aed8dd..dd64e49c2de 100644
--- a/be/src/core/column/variant_v2/column_variant_v2_read_view.cpp
+++ b/be/src/core/column/variant_v2/column_variant_v2_read_view.cpp
@@ -15,21 +15,13 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include "core/assert_cast.h"
-#include "core/column/column_string.h"
-#include "core/column/column_vector.h"
 #include "core/column/variant_v2/column_variant_v2.h"
 
 namespace doris {
 
-namespace {
-
-using MetadataIdsColumn = ColumnVector<TYPE_UINT32>;
-
-} // namespace
-
-ColumnVariantV2::ReadView::ReadView(const IColumn* metadatas, const IColumn* 
metadata_ids,
-                                    const IColumn* values)
+ColumnVariantV2::ReadView::ReadView(const ColumnString* metadatas,
+                                    const MetadataIdsColumn* metadata_ids,
+                                    const ColumnString* values)
         : _metadatas(metadatas), _metadata_ids(metadata_ids), _values(values) {
     DORIS_CHECK(_metadatas != nullptr);
     DORIS_CHECK(_metadata_ids != nullptr);
@@ -57,7 +49,7 @@ size_t ColumnVariantV2::ReadView::metadata_count() const 
noexcept {
 uint32_t ColumnVariantV2::ReadView::metadata_id_at(size_t row) const {
     DORIS_CHECK(!_typed_state) << "metadata_id_at requires ColumnVariantV2 
encoded state";
     DORIS_CHECK_LT(row, size()) << "ColumnVariantV2 encoded read row is out of 
range";
-    const auto& ids = assert_cast<const 
MetadataIdsColumn&>(*_metadata_ids).get_data();
+    const auto& ids = _metadata_ids->get_data();
     const uint32_t id = ids[row];
     DORIS_CHECK_LT(id, metadata_count())
             << "ColumnVariantV2 encoded read metadata id is out of range";
@@ -67,14 +59,14 @@ uint32_t ColumnVariantV2::ReadView::metadata_id_at(size_t 
row) const {
 VariantMetadataRef ColumnVariantV2::ReadView::metadata_at(uint32_t id) const {
     DORIS_CHECK(!_typed_state) << "metadata_at requires ColumnVariantV2 
encoded state";
     DORIS_CHECK_LT(id, metadata_count()) << "ColumnVariantV2 encoded read 
metadata is out of range";
-    const StringRef metadata = assert_cast<const 
ColumnString&>(*_metadatas).get_data_at(id);
+    const StringRef metadata = _metadatas->get_data_at(id);
     return {.data = metadata.data, .size = metadata.size};
 }
 
 VariantRef ColumnVariantV2::ReadView::value_at(size_t row) const {
     DORIS_CHECK(!_typed_state) << "value_at requires ColumnVariantV2 encoded 
state";
     const uint32_t metadata_id = metadata_id_at(row);
-    const StringRef value = assert_cast<const 
ColumnString&>(*_values).get_data_at(row);
+    const StringRef value = _values->get_data_at(row);
     return {.metadata = metadata_at(metadata_id), .value = value};
 }
 
@@ -94,9 +86,7 @@ ColumnVariantV2::ReadView ColumnVariantV2::read_view() const {
         return {static_cast<const IColumn::Ptr&>(_typed).get(), &_typed_type};
     }
     DORIS_CHECK(_typed_type == nullptr) << "encoded state cannot retain a 
typed data type";
-    return {static_cast<const IColumn::Ptr&>(_metadatas).get(),
-            static_cast<const IColumn::Ptr&>(_meta_ids).get(),
-            static_cast<const IColumn::Ptr&>(_values).get()};
+    return {_metadatas.get(), _meta_ids.get(), _values.get()};
 }
 
 } // namespace doris
diff --git a/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp 
b/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
index a9a137e4fea..f08509e6769 100644
--- a/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
@@ -251,9 +251,12 @@ const char* DataTypeVariantV2SerDe::deserialize(const 
char* buf, MutableColumnPt
             }
         }
         decoded = ColumnVariantV2::create();
-        static_cast<IColumn::Ptr&>(decoded->_metadatas) = std::move(metadatas);
-        static_cast<IColumn::Ptr&>(decoded->_meta_ids) = std::move(meta_ids);
-        static_cast<IColumn::Ptr&>(decoded->_values) = std::move(values);
+        static_cast<ColumnString::Ptr&>(decoded->_metadatas) =
+                ColumnString::cast_to_column_ptr(assert_cast<const 
ColumnString*>(metadatas.get()));
+        static_cast<MetaIdsColumn::Ptr&>(decoded->_meta_ids) = 
MetaIdsColumn::cast_to_column_ptr(
+                assert_cast<const MetaIdsColumn*>(meta_ids.get()));
+        static_cast<ColumnString::Ptr&>(decoded->_values) =
+                ColumnString::cast_to_column_ptr(assert_cast<const 
ColumnString*>(values.get()));
         decoded->sanity_check();
     }
     if (decoded->size() != saved_rows) {
diff --git a/be/test/core/column/column_variant_v2_test.cpp 
b/be/test/core/column/column_variant_v2_test.cpp
index 2665304cfa0..1a3b9ff7d45 100644
--- a/be/test/core/column/column_variant_v2_test.cpp
+++ b/be/test/core/column/column_variant_v2_test.cpp
@@ -319,10 +319,6 @@ uint32_t canonical_crc32c_hash(VariantRef value, uint32_t 
seed) {
     return sink.digest();
 }
 
-void replace_subcolumn(ColumnVariantV2& column, size_t target, ColumnPtr 
replacement) {
-    ColumnVariantV2::TestAccess::replace_encoded_subcolumn(column, target, 
std::move(replacement));
-}
-
 ColumnPtr nullable_int32(std::span<const int32_t> values, std::span<const 
uint8_t> null_map) {
     EXPECT_EQ(values.size(), null_map.size());
     auto nested = ColumnInt32::create();
@@ -1793,7 +1789,7 @@ TEST(ColumnVariantV2Test, EncodedRowCountInvariant) {
             {
                 auto column = ColumnVariantV2::create();
                 insert_encoded_field(*column, encode_json("1"));
-                replace_subcolumn(*column, 2, ColumnString::create());
+                ColumnVariantV2::TestAccess::replace_values(*column, 
ColumnString::create());
                 column->sanity_check();
             },
             "encoded row counts differ");
@@ -1806,7 +1802,7 @@ TEST(ColumnVariantV2Test, MetadataIdInvariant) {
                 insert_encoded_field(*column, encode_json("1"));
                 auto invalid_ids = MetaIdsColumn::create();
                 invalid_ids->insert_value(9);
-                replace_subcolumn(*column, 1, invalid_ids->get_ptr());
+                ColumnVariantV2::TestAccess::replace_metadata_ids(*column, 
std::move(invalid_ids));
                 column->sanity_check();
             },
             "metadata id is out of range");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to