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

eldenmoon pushed a commit to branch variant-sparse
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/variant-sparse by this push:
     new aff912b8672 [opt](variant) add serialized sparse column (#45252)
aff912b8672 is described below

commit aff912b8672c859d980632904f25d88ba654cba8
Author: Sun Chenyang <suncheny...@selectdb.com>
AuthorDate: Tue Dec 10 19:13:14 2024 +0800

    [opt](variant) add serialized sparse column (#45252)
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #xxx
    
    Problem Summary:
    
    ### 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 -->
---
 be/src/vec/columns/column_object.cpp          | 293 +++++++++++++++++++++++---
 be/src/vec/columns/column_object.h            |  67 ++++--
 be/src/vec/data_types/serde/data_type_serde.h |   5 +
 3 files changed, 318 insertions(+), 47 deletions(-)

diff --git a/be/src/vec/columns/column_object.cpp 
b/be/src/vec/columns/column_object.cpp
index 2983d799166..c1a50f6064b 100644
--- a/be/src/vec/columns/column_object.cpp
+++ b/be/src/vec/columns/column_object.cpp
@@ -51,6 +51,7 @@
 #include "vec/aggregate_functions/helpers.h"
 #include "vec/columns/column.h"
 #include "vec/columns/column_array.h"
+#include "vec/columns/column_map.h"
 #include "vec/columns/column_nullable.h"
 #include "vec/columns/column_string.h"
 #include "vec/columns/column_vector.h"
@@ -982,6 +983,43 @@ void ColumnObject::Subcolumn::get(size_t n, Field& res) 
const {
                            n);
 }
 
+void ColumnObject::Subcolumn::serialize_to_sparse_column(ColumnString* key, 
std::string_view path,
+                                                         ColumnString* value, 
size_t row,
+                                                         bool& is_null) {
+    // no need insert
+    if (least_common_type.get_base_type_id() == TypeIndex::Nothing) {
+        is_null = true;
+        return;
+    }
+
+    // no need insert
+    if (row < num_of_defaults_in_prefix) {
+        is_null = true;
+        return;
+    }
+
+    // remove default
+    row -= num_of_defaults_in_prefix;
+    is_null = false;
+    for (size_t i = 0; i < data.size(); ++i) {
+        const auto& part = data[i];
+        if (row < part->size()) {
+            // insert key
+            key->insert_data(path.data(), path.size());
+            // insert value
+            const auto& part_type = data_types[i];
+            const auto& serde = part_type->get_serde();
+            serde->write_one_cell_to_binary(*part, value, row);
+            return;
+        }
+
+        row -= part->size();
+    }
+
+    throw doris::Exception(ErrorCode::OUT_OF_BOUND,
+                           "Index ({}) for serialize to sparse column is out 
of range", row);
+}
+
 Field ColumnObject::operator[](size_t n) const {
     Field object;
     get(n, object);
@@ -1062,35 +1100,48 @@ void ColumnObject::add_nested_subcolumn(const 
PathInData& key, const FieldInfo&
     }
 }
 
+bool ColumnObject::try_add_new_subcolumn(const PathInData& path) {
+    if (subcolumns.size() == MAX_SUBCOLUMNS) return false;
+
+    return add_sub_column(path, num_rows);
+}
+
 void ColumnObject::insert_range_from(const IColumn& src, size_t start, size_t 
length) {
 #ifndef NDEBUG
     check_consistency();
 #endif
     const auto& src_object = assert_cast<const ColumnObject&>(src);
+
+    // First, insert src subcolumns
+    // We can reach the limit of subcolumns, and in this case
+    // the rest of subcolumns from src will be inserted into sparse column.
+    std::map<std::string_view, Subcolumn> 
src_path_and_subcoumn_for_sparse_column;
     for (const auto& entry : src_object.subcolumns) {
-        if (!has_subcolumn(entry->path)) {
-            if (entry->path.has_nested_part()) {
-                FieldInfo field_info {
-                        .scalar_type_id = 
entry->data.least_common_type.get_base_type_id(),
-                        .have_nulls = false,
-                        .need_convert = false,
-                        .num_dimensions = entry->data.get_dimensions()};
-                add_nested_subcolumn(entry->path, field_info, num_rows);
-            } else {
-                add_sub_column(entry->path, num_rows);
-            }
+        // Check if we already have such dense column path.
+        if (auto* subcolumn = get_subcolumn(entry->path); subcolumn != 
nullptr) {
+            subcolumn->insert_range_from(entry->data, start, length);
+        } else if (try_add_new_subcolumn(entry->path)) {
+            subcolumn = get_subcolumn(entry->path);
+            DCHECK(subcolumn != nullptr);
+            subcolumn->insert_range_from(entry->data, start, length);
+        } else {
+            
src_path_and_subcoumn_for_sparse_column.emplace(entry->path.get_path(), 
entry->data);
         }
-        auto* subcolumn = get_subcolumn(entry->path);
-        subcolumn->insert_range_from(entry->data, start, length);
     }
-    for (auto& entry : subcolumns) {
-        if (!src_object.has_subcolumn(entry->path)) {
-            bool inserted = try_insert_many_defaults_from_nested(entry);
-            if (!inserted) {
-                entry->data.insert_many_defaults(length);
-            }
-        }
+
+    // Paths in sparse column are sorted, so paths from 
src_dense_column_path_for_sparse_column should be inserted properly
+    // to keep paths sorted. Let's sort them in advance.
+    std::vector<std::pair<std::string_view, Subcolumn>> 
sorted_src_subcolumn_for_sparse_column;
+    auto it = src_path_and_subcoumn_for_sparse_column.begin();
+    auto end = src_path_and_subcoumn_for_sparse_column.end();
+    while (it != end) {
+        sorted_src_subcolumn_for_sparse_column.emplace_back(it->first, 
it->second);
+        ++it;
     }
+
+    insert_from_sparse_column_and_fill_remaing_dense_column(
+            src_object, std::move(sorted_src_subcolumn_for_sparse_column), 
start, length);
+
     num_rows += length;
     finalize();
 #ifndef NDEBUG
@@ -1098,6 +1149,141 @@ void ColumnObject::insert_range_from(const IColumn& 
src, size_t start, size_t le
 #endif
 }
 
+// std::map<std::string_view, Subcolumn>
+void ColumnObject::insert_from_sparse_column_and_fill_remaing_dense_column(
+        const ColumnObject& src,
+        std::vector<std::pair<std::string_view, Subcolumn>>&&
+                sorted_src_subcolumn_for_sparse_column,
+        size_t start, size_t length) {
+    /// Check if src object doesn't have any paths in serialized sparse column.
+    const auto& src_serialized_sparse_column_offsets = 
src.serialized_sparse_column_offsets();
+    if (src_serialized_sparse_column_offsets[start - 1] ==
+        src_serialized_sparse_column_offsets[start + length - 1]) {
+        size_t current_size = size();
+
+        /// If no src subcolumns should be inserted into sparse column, insert 
defaults.
+        if (sorted_src_subcolumn_for_sparse_column.empty()) {
+            serialized_sparse_column->insert_many_defaults(length);
+        } else {
+            // Otherwise insert required src dense columns into sparse column.
+            auto [sparse_column_keys, sparse_column_values] = 
get_sparse_data_paths_and_values();
+            auto& sparse_column_offsets = serialized_sparse_column_offsets();
+            for (size_t i = start; i != start + length; ++i) {
+                int null_count = 0;
+                // Paths in sorted_src_subcolumn_for_sparse_column are already 
sorted.
+                for (auto& [path, subcolumn] : 
sorted_src_subcolumn_for_sparse_column) {
+                    bool is_null = false;
+                    subcolumn.serialize_to_sparse_column(sparse_column_keys, 
path,
+                                                         sparse_column_values, 
i, is_null);
+                    if (is_null) {
+                        ++null_count;
+                    }
+                }
+
+                // All the sparse columns in this row are null.
+                if (null_count == 
sorted_src_subcolumn_for_sparse_column.size()) {
+                    serialized_sparse_column->insert_default();
+                } else {
+                    DCHECK_EQ(sparse_column_keys->size(),
+                              sparse_column_offsets[i - 1] +
+                                      
sorted_src_subcolumn_for_sparse_column.size() - null_count);
+                    DCHECK_EQ(sparse_column_values->size(), 
sparse_column_keys->size());
+                    
sparse_column_offsets.push_back(sparse_column_keys->size());
+                }
+            }
+        }
+
+        // Insert default values in all remaining dense columns.
+        for (const auto& entry : subcolumns) {
+            if (entry->data.size() == current_size) {
+                entry->data.insert_many_defaults(length);
+            }
+        }
+        return;
+    }
+
+    // Src object column contains some paths in serialized sparse column in 
specified range.
+    // Iterate over this range and insert all required paths into serialized 
sparse column or subcolumns.
+    const auto& [src_sparse_column_path, src_sparse_column_values] =
+            src.get_sparse_data_paths_and_values();
+    auto [sparse_column_path, sparse_column_values] = 
get_sparse_data_paths_and_values();
+
+    auto& sparse_column_offsets = serialized_sparse_column_offsets();
+    for (size_t row = start; row != start + length; ++row) {
+        size_t current_size = sparse_column_offsets.size();
+
+        // Use separate index to iterate over sorted 
sorted_src_subcolumn_for_sparse_column.
+        size_t sorted_src_subcolumn_for_sparse_column_idx = 0;
+        size_t sorted_src_subcolumn_for_sparse_column_size =
+                sorted_src_subcolumn_for_sparse_column.size();
+        int null_count = 0;
+
+        size_t offset = src_serialized_sparse_column_offsets[row - 1];
+        size_t end = src_serialized_sparse_column_offsets[row];
+        // Iterator over [path, binary value]
+        for (size_t i = offset; i != end; ++i) {
+            const StringRef src_sparse_path_string = 
src_sparse_column_path->get_data_at(i);
+            const std::string_view src_sparse_path(src_sparse_path_string);
+            // Check if we have this path in subcolumns.
+            const PathInData column_path(src_sparse_path);
+            if (auto* subcolumn = get_subcolumn(column_path); subcolumn != 
nullptr) {
+                // Deserialize binary value into subcolumn from src serialized 
sparse column data.
+                
subcolumn->deserialize_from_sparse_column(src_sparse_column_values, i);
+            } else {
+                // Before inserting this path into sparse column check if we 
need to
+                // insert suibcolumns from 
sorted_src_subcolumn_for_sparse_column before.
+                while (sorted_src_subcolumn_for_sparse_column_idx <
+                               sorted_src_subcolumn_for_sparse_column_size &&
+                       sorted_src_subcolumn_for_sparse_column
+                                       
[sorted_src_subcolumn_for_sparse_column_idx]
+                                               .first < src_sparse_path) {
+                    auto& [src_path, src_subcolumn] = 
sorted_src_subcolumn_for_sparse_column
+                            [sorted_src_subcolumn_for_sparse_column_idx++];
+                    bool is_null = false;
+                    
src_subcolumn.serialize_to_sparse_column(sparse_column_path, src_path,
+                                                             
sparse_column_values, row, is_null);
+                    if (is_null) {
+                        ++null_count;
+                    }
+                }
+
+                /// Insert path and value from src sparse column to our sparse 
column.
+                sparse_column_path->insert_from(*src_sparse_column_path, i);
+                sparse_column_values->insert_from(*src_sparse_column_values, 
i);
+            }
+        }
+
+        // Insert remaining dynamic paths from 
src_dynamic_paths_for_shared_data.
+        while (sorted_src_subcolumn_for_sparse_column_idx <
+               sorted_src_subcolumn_for_sparse_column_size) {
+            auto& [src_path, src_subcolumn] = 
sorted_src_subcolumn_for_sparse_column
+                    [sorted_src_subcolumn_for_sparse_column_idx++];
+            bool is_null = false;
+            src_subcolumn.serialize_to_sparse_column(sparse_column_path, 
src_path,
+                                                     sparse_column_values, 
row, is_null);
+            if (is_null) {
+                ++null_count;
+            }
+        }
+
+        // All the sparse columns in this row are null.
+        if (null_count == sorted_src_subcolumn_for_sparse_column.size()) {
+            serialized_sparse_column->insert_default();
+        } else {
+            sparse_column_offsets.push_back(sparse_column_path->size());
+        }
+
+        // Insert default values in all remaining dense columns.
+        for (const auto& entry : subcolumns) {
+            if (entry->data.size() == current_size) {
+                entry->data.insert_default();
+            }
+        }
+    }
+
+    return;
+}
+
 ColumnPtr ColumnObject::replicate(const Offsets& offsets) const {
     if (subcolumns.empty()) {
         // Add an emtpy column with offsets.back rows
@@ -1514,6 +1700,47 @@ size_t 
ColumnObject::Subcolumn::get_non_null_value_size() const {
     return res;
 }
 
+Status ColumnObject::serialize_sparse_columns(
+        std::map<std::string_view, Subcolumn>&& remaing_subcolumns) {
+    CHECK(is_finalized());
+
+    serialized_sparse_column = ColumnMap::create(ColumnString::create(), 
ColumnString::create(),
+                                                 
ColumnArray::ColumnOffsets::create());
+    if (remaing_subcolumns.empty()) {
+        serialized_sparse_column->insert_many_defaults(num_rows);
+        return Status::OK();
+    }
+    serialized_sparse_column->reserve(num_rows);
+    auto [sparse_column_keys, sparse_column_values] = 
get_sparse_data_paths_and_values();
+    auto& sparse_column_offsets = serialized_sparse_column_offsets();
+
+    // Fill the column map for each row
+    for (size_t i = 0; i < num_rows; ++i) {
+        int null_count = 0;
+
+        for (auto& [path, subcolumn] : remaing_subcolumns) {
+            bool is_null = false;
+            subcolumn.serialize_to_sparse_column(sparse_column_keys, path, 
sparse_column_values, i,
+                                                 is_null);
+            if (is_null) {
+                ++null_count;
+            }
+        }
+
+        // All the sparse columns in this row are null.
+        if (null_count == remaing_subcolumns.size()) {
+            serialized_sparse_column->insert_default();
+        } else {
+            DCHECK_EQ(sparse_column_keys->size(),
+                      sparse_column_offsets[i - 1] + remaing_subcolumns.size() 
- null_count);
+            DCHECK_EQ(sparse_column_values->size(), 
sparse_column_keys->size());
+            sparse_column_offsets.push_back(sparse_column_keys->size());
+        }
+    }
+    CHECK_EQ(serialized_sparse_column->size(), num_rows);
+    return Status::OK();
+}
+
 void ColumnObject::unnest(Subcolumns::NodePtr& entry, Subcolumns& subcolumns) 
const {
     entry->data.finalize();
     auto nested_column = 
entry->data.get_finalized_column_ptr()->assume_mutable();
@@ -1558,11 +1785,11 @@ Status ColumnObject::finalize(FinalizeMode mode) {
     }
 
     // pick sparse columns
-    std::set<String> selected_subcolumns;
-    std::set<String> remaining_subcolumns;
+    std::set<std::string_view> selected_path;
+    std::vector<std::string_view> remaining_path;
     if (subcolumns.size() > MAX_SUBCOLUMNS) {
         // pick subcolumns sort by size of none null values
-        std::unordered_map<String, size_t> none_null_value_sizes;
+        std::unordered_map<std::string_view, size_t> none_null_value_sizes;
         // 1. get the none null value sizes
         for (auto&& entry : subcolumns) {
             if (entry->data.is_root) {
@@ -1572,22 +1799,20 @@ Status ColumnObject::finalize(FinalizeMode mode) {
             none_null_value_sizes[entry->path.get_path()] = size;
         }
         // 2. sort by the size
-        std::vector<std::pair<String, size_t>> 
sorted_by_size(none_null_value_sizes.begin(),
-                                                              
none_null_value_sizes.end());
+        std::vector<std::pair<std::string_view, size_t>> sorted_by_size(
+                none_null_value_sizes.begin(), none_null_value_sizes.end());
         std::sort(sorted_by_size.begin(), sorted_by_size.end(),
                   [](const auto& a, const auto& b) { return a.second > 
b.second; });
 
         // 3. pick MAX_SUBCOLUMNS selected subcolumns
-        std::set<String> selected_subcolumns;
         for (size_t i = 0; i < std::min(MAX_SUBCOLUMNS, 
sorted_by_size.size()); ++i) {
-            selected_subcolumns.insert(sorted_by_size[i].first);
+            selected_path.insert(sorted_by_size[i].first);
         }
 
         // 4. put remaining subcolumns to remaining_subcolumns
-        std::vector<String> remaining_subcolumns;
         for (const auto& entry : sorted_by_size) {
-            if (selected_subcolumns.find(entry.first) == 
selected_subcolumns.end()) {
-                remaining_subcolumns.push_back(entry.first);
+            if (selected_path.find(entry.first) == selected_path.end()) {
+                remaining_path.emplace_back(entry.first);
             }
         }
     }
@@ -1617,21 +1842,21 @@ Status ColumnObject::finalize(FinalizeMode mode) {
 
     // add selected subcolumns to new_subcolumns
     for (auto&& entry : subcolumns) {
-        if (selected_subcolumns.find(entry->path.get_path()) != 
selected_subcolumns.end()) {
+        if (selected_path.find(entry->path.get_path()) != selected_path.end()) 
{
             new_subcolumns.add(entry->path, entry->data);
         }
     }
 
-    std::map<String, Subcolumn> remaing_subcolumns;
+    std::map<std::string_view, Subcolumn> remaing_subcolumns;
     // merge remaining subcolumns to sparse_column
     for (auto&& entry : subcolumns) {
-        if (remaining_subcolumns.find(entry->path.get_path()) != 
selected_subcolumns.end()) {
+        if (selected_path.find(entry->path.get_path()) != selected_path.end()) 
{
             remaing_subcolumns.emplace(entry->path.get_path(), entry->data);
         }
     }
 
     // merge and encode sparse column
-    RETURN_IF_ERROR(merge_sparse_columns(remaing_subcolumns));
+    RETURN_IF_ERROR(serialize_sparse_columns(std::move(remaing_subcolumns)));
 
     std::swap(subcolumns, new_subcolumns);
     doc_structure = nullptr;
diff --git a/be/src/vec/columns/column_object.h 
b/be/src/vec/columns/column_object.h
index 1475a168c23..38ed5478f02 100644
--- a/be/src/vec/columns/column_object.h
+++ b/be/src/vec/columns/column_object.h
@@ -98,7 +98,7 @@ public:
     constexpr static TypeIndex MOST_COMMON_TYPE_ID = TypeIndex::JSONB;
     // Nullable(Array(Nullable(Object)))
     const static DataTypePtr NESTED_TYPE;
-    const static size_t MAX_SUBCOLUMNS = 200;
+    const size_t MAX_SUBCOLUMNS = 200;
     // Finlize mode for subcolumns, write mode will estimate which subcolumns 
are sparse columns(too many null values inside column),
     // merge and encode them into a shared column in root column. Only affects 
in flush block to segments.
     // Otherwise read mode should be as default mode.
@@ -181,6 +181,13 @@ public:
 
         void add_new_column_part(DataTypePtr type);
 
+        // Serialize the i-th row of the column into the sparse column.
+        void serialize_to_sparse_column(ColumnString* key, std::string_view 
path,
+                                        ColumnString* value, size_t row, bool& 
is_null);
+
+        // Deserialize the i-th row of the column from the sparse column.
+        void deserialize_from_sparse_column(const ColumnString* value, size_t 
row) {}
+
         friend class ColumnObject;
 
     private:
@@ -244,13 +251,20 @@ private:
     const bool is_nullable;
     Subcolumns subcolumns;
     size_t num_rows;
-    // sparse columns will be merge and encoded as ColumnMap<String, String>
-    WrappedPtr sparse_column;
+
+    // The rapidjson document format of Subcolumns tree structure
+    // the leaves is null.In order to display whole document, copy
+    // this structure and fill with Subcolumns sub items
+    mutable std::shared_ptr<rapidjson::Document> doc_structure;
 
     using SubColumnWithName = std::pair<PathInData, const Subcolumn*>;
     // Cached search results for previous row (keyed as index in JSON object) 
- used as a hint.
     mutable std::vector<SubColumnWithName> _prev_positions;
 
+    // It's filled when the number of subcolumns reaches the limit.
+    // It has type Map(String, String) and stores a map (path, binary 
serialized subcolumn value) for each row.
+    WrappedPtr serialized_sparse_column;
+
 public:
     static constexpr auto COLUMN_NAME_DUMMY = "_dummy";
 
@@ -280,19 +294,12 @@ public:
     Status serialize_one_row_to_json_format(int64_t row, 
rapidjson::StringBuffer* output,
                                             bool* is_null) const;
 
-    // merge multiple sub sparse columns
-    Status merge_sparse_columns(const std::map<String, Subcolumn>& 
remaing_subcolumns);
+    // Fill the `serialized_sparse_column`
+    Status serialize_sparse_columns(std::map<std::string_view, Subcolumn>&& 
remaing_subcolumns);
 
     // ensure root node is a certain type
     void ensure_root_node_type(const DataTypePtr& type);
 
-    std::pair<ColumnString*, ColumnString*> get_sparse_data_paths_and_values() 
{
-        auto& column_map = assert_cast<ColumnMap&>(*sparse_column);
-        auto& key = assert_cast<ColumnString&>(column_map.get_keys());
-        auto& value = assert_cast<ColumnString&>(column_map.get_values());
-        return {&key, &value};
-    }
-
     // create jsonb root if missing
     // notice: should only using in VariantRootColumnIterator
     // since some datastructures(sparse columns are schema on read
@@ -354,7 +361,9 @@ public:
 
     Subcolumns& get_subcolumns() { return subcolumns; }
 
-    ColumnPtr get_sparse_column() { return 
sparse_column->convert_to_full_column_if_const(); }
+    ColumnPtr get_sparse_column() {
+        return serialized_sparse_column->convert_to_full_column_if_const();
+    }
 
     PathsInData getKeys() const;
 
@@ -556,6 +565,20 @@ public:
                                "replace_column_data" + get_name());
     }
 
+    std::pair<ColumnString*, ColumnString*> get_sparse_data_paths_and_values() 
{
+        auto& column_map = assert_cast<ColumnMap&>(*serialized_sparse_column);
+        auto& key = assert_cast<ColumnString&>(column_map.get_keys());
+        auto& value = assert_cast<ColumnString&>(column_map.get_values());
+        return {&key, &value};
+    }
+
+    std::pair<const ColumnString*, const ColumnString*> 
get_sparse_data_paths_and_values() const {
+        const auto& column_map = assert_cast<const 
ColumnMap&>(*serialized_sparse_column);
+        const auto& key = assert_cast<const 
ColumnString&>(column_map.get_keys());
+        const auto& value = assert_cast<const 
ColumnString&>(column_map.get_values());
+        return {&key, &value};
+    }
+
 private:
     // May throw execption
     void try_insert(const Field& field);
@@ -570,6 +593,24 @@ private:
 
     // unnest nested type columns, and flat them into finlized array subcolumns
     void unnest(Subcolumns::NodePtr& entry, Subcolumns& subcolumns) const;
+
+    ColumnArray::Offsets64& ALWAYS_INLINE serialized_sparse_column_offsets() {
+        auto& column_map = assert_cast<ColumnMap&>(*serialized_sparse_column);
+        return column_map.get_offsets();
+    }
+
+    const ColumnArray::Offsets64& ALWAYS_INLINE 
serialized_sparse_column_offsets() const {
+        const auto& column_map = assert_cast<const 
ColumnMap&>(*serialized_sparse_column);
+        return column_map.get_offsets();
+    }
+
+    void insert_from_sparse_column_and_fill_remaing_dense_column(
+            const ColumnObject& src,
+            std::vector<std::pair<std::string_view, Subcolumn>>&&
+                    sorted_src_subcolumn_for_sparse_column,
+            size_t start, size_t length);
+
+    bool try_add_new_subcolumn(const PathInData& path);
 };
 
 } // namespace doris::vectorized
diff --git a/be/src/vec/data_types/serde/data_type_serde.h 
b/be/src/vec/data_types/serde/data_type_serde.h
index f0e9eb27961..5b0e8fab65e 100644
--- a/be/src/vec/data_types/serde/data_type_serde.h
+++ b/be/src/vec/data_types/serde/data_type_serde.h
@@ -337,6 +337,11 @@ public:
                                           Arena& mem_pool, int64_t row_num) 
const;
     virtual Status read_one_cell_from_json(IColumn& column, const 
rapidjson::Value& result) const;
 
+    virtual void write_one_cell_to_binary(const IColumn& src_column, 
ColumnString* dst_column,
+                                          int64_t row_num) {
+        throw doris::Exception(ErrorCode::NOT_IMPLEMENTED_ERROR, 
"write_one_cell_to_binary");
+    }
+
 protected:
     bool _return_object_as_string = false;
     // This parameter indicates what level the serde belongs to and is mainly 
used for complex types


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to