diff --git a/be/src/core/column/column_variant.cpp b/be/src/core/column/column_variant.cpp index e6bf0f45deae3e..050709401aff2a 100644 --- a/be/src/core/column/column_variant.cpp +++ b/be/src/core/column/column_variant.cpp @@ -2488,64 +2488,33 @@ bool ColumnVariant::try_insert_many_defaults_from_nested(const Subcolumns::NodeP return true; } -/// Visitor that keeps @num_dimensions_to_keep dimensions in arrays -/// and replaces all scalars or nested arrays to @replacement at that level. -class FieldVisitorReplaceScalars : public StaticVisitor { -public: - FieldVisitorReplaceScalars(const Field& replacement_, size_t num_dimensions_to_keep_) - : replacement(replacement_), num_dimensions_to_keep(num_dimensions_to_keep_) {} - - template - Field apply(const typename PrimitiveTypeTraits::CppType& x) const { - if constexpr (T == TYPE_ARRAY) { - if (num_dimensions_to_keep == 0) { - return replacement; - } - - const size_t size = x.size(); - Array res(size); - for (size_t i = 0; i < size; ++i) { - res[i] = apply_visitor( - FieldVisitorReplaceScalars(replacement, num_dimensions_to_keep - 1), x[i]); - } - return Field::create_field(res); - } else { - return replacement; - } - } - -private: - const Field& replacement; - size_t num_dimensions_to_keep; -}; - bool ColumnVariant::try_insert_default_from_nested(const Subcolumns::NodePtr& entry) const { const auto* leaf = get_leaf_of_the_same_nested(entry); if (!leaf) { return false; } - auto last_field = leaf->data.get_last_field(); - if (last_field.is_null()) { + size_t leaf_size = leaf->data.size(); + if (leaf_size == 0) { return false; } - size_t leaf_num_dimensions = leaf->data.get_dimensions(); - size_t entry_num_dimensions = entry->data.get_dimensions(); - - if (entry_num_dimensions > leaf_num_dimensions) { - throw doris::Exception( - ErrorCode::INVALID_ARGUMENT, - "entry_num_dimensions > leaf_num_dimensions, entry_num_dimensions={}, " - "leaf_num_dimensions={}", - entry_num_dimensions, leaf_num_dimensions); + // Preserve the original null guard: if the donor leaf's last row is NULL, + // fall back to insert_default() so that a missing sibling stays NULL too. + if (leaf->data.is_null_at(leaf_size - 1)) { + return false; } - auto default_scalar = entry->data.get_least_common_type()->get_default(); + FieldInfo field_info = { + .scalar_type_id = entry->data.least_common_type.get_base_type_id(), + .num_dimensions = entry->data.get_dimensions(), + }; - auto default_field = apply_visitor( - FieldVisitorReplaceScalars(default_scalar, leaf_num_dimensions), last_field); - entry->data.insert(std::move(default_field)); + // Reuse the same column-level approach as try_insert_many_defaults_from_nested: + // cut the last row from leaf, replace scalar values with defaults, keep array structure. + auto new_subcolumn = leaf->data.cut(leaf_size - 1, 1).clone_with_default_values(field_info); + entry->data.insert_range_from(new_subcolumn, 0, 1); + ENABLE_CHECK_CONSISTENCY(this); return true; } diff --git a/be/src/exec/common/variant_util.cpp b/be/src/exec/common/variant_util.cpp index e8f57d991e1e22..57fc440ba2a45a 100644 --- a/be/src/exec/common/variant_util.cpp +++ b/be/src/exec/common/variant_util.cpp @@ -1821,35 +1821,6 @@ static void append_field_to_binary_chars(const Field& field, ColumnString::Chars field.get_type()); } } -/// Visitor that keeps @num_dimensions_to_keep dimensions in arrays -/// and replaces all scalars or nested arrays to @replacement at that level. -class FieldVisitorReplaceScalars : public StaticVisitor { -public: - FieldVisitorReplaceScalars(const Field& replacement_, size_t num_dimensions_to_keep_) - : replacement(replacement_), num_dimensions_to_keep(num_dimensions_to_keep_) {} - template - Field operator()(const typename PrimitiveTypeTraits::CppType& x) const { - if constexpr (T == TYPE_ARRAY) { - if (num_dimensions_to_keep == 0) { - return replacement; - } - const size_t size = x.size(); - Array res(size); - for (size_t i = 0; i < size; ++i) { - res[i] = apply_visitor( - FieldVisitorReplaceScalars(replacement, num_dimensions_to_keep - 1), x[i]); - } - return Field::create_field(res); - } else { - return replacement; - } - } - -private: - const Field& replacement; - size_t num_dimensions_to_keep; -}; - template void parse_json_to_variant_impl(IColumn& column, const char* src, size_t length, JSONDataParser* parser, const ParseConfig& config) { diff --git a/be/test/core/column/column_variant_test.cpp b/be/test/core/column/column_variant_test.cpp index 8c9549a7daeb40..9825f836186eb6 100644 --- a/be/test/core/column/column_variant_test.cpp +++ b/be/test/core/column/column_variant_test.cpp @@ -3082,30 +3082,6 @@ TEST_F(ColumnVariantTest, get_field_info_all_types) { } } -TEST_F(ColumnVariantTest, field_visitor) { - // Test replacing scalar values in a flat array - { - Array array; - array.push_back(Field::create_field(Int64(1))); - array.push_back(Field::create_field(Int64(2))); - array.push_back(Field::create_field(Int64(3))); - - Field field = Field::create_field(std::move(array)); - Field replacement = Field::create_field(Int64(42)); - Field result = apply_visitor(FieldVisitorReplaceScalars(replacement, 0), field); - - EXPECT_EQ(result.get(), 42); - - Field replacement1 = Field::create_field(Int64(42)); - Field result1 = apply_visitor(FieldVisitorReplaceScalars(replacement, 1), field); - - EXPECT_EQ(result1.get().size(), 3); - EXPECT_EQ(result1.get()[0].get(), 42); - EXPECT_EQ(result1.get()[1].get(), 42); - EXPECT_EQ(result1.get()[2].get(), 42); - } -} - TEST_F(ColumnVariantTest, subcolumn_operations_coverage) { // Test insert_range_from {