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

zclll 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 17a81a419a4 [check](column)const is only allowed at the top level. 
(#60578)
17a81a419a4 is described below

commit 17a81a419a469e4b9ccae0dafc94d962d70d6797
Author: Mryange <[email protected]>
AuthorDate: Mon Mar 2 19:14:45 2026 +0800

    [check](column)const is only allowed at the top level. (#60578)
    
    check nested const occurrences; const is only allowed at the top level.
    e.g. const(nullable(...)) is allowed.
    const(array(const(...))) is not allowed.
---
 be/src/vec/columns/column.cpp                      |  11 +
 be/src/vec/columns/column.h                        |   5 +
 be/src/vec/columns/column_array.cpp                |   4 +-
 be/src/vec/columns/column_map.cpp                  |   1 +
 be/src/vec/columns/column_nullable.cpp             |   4 +-
 be/src/vec/columns/column_struct.cpp               |   1 +
 be/test/vec/columns/column_array_test.cpp          |  73 +++--
 .../column_check_const_only_in_top_level_test.cpp  | 311 +++++++++++++++++++++
 8 files changed, 366 insertions(+), 44 deletions(-)

diff --git a/be/src/vec/columns/column.cpp b/be/src/vec/columns/column.cpp
index b206fc17034..68777b37240 100644
--- a/be/src/vec/columns/column.cpp
+++ b/be/src/vec/columns/column.cpp
@@ -230,4 +230,15 @@ bool is_column_const(const IColumn& column) {
     return is_column<ColumnConst>(column);
 }
 
+void IColumn::check_const_only_in_top_level() const {
+    ColumnCallback throw_if_const = [&](WrappedPtr& column) {
+        if (is_column_const(*column)) {
+            throw doris::Exception(ErrorCode::INTERNAL_ERROR,
+                                   "const column is not allowed to be nested, 
but got {}",
+                                   column->get_name());
+        }
+    };
+    const_cast<IColumn*>(this)->for_each_subcolumn(throw_if_const);
+}
+
 } // namespace doris::vectorized
diff --git a/be/src/vec/columns/column.h b/be/src/vec/columns/column.h
index d0aa6970af5..3e89aec134a 100644
--- a/be/src/vec/columns/column.h
+++ b/be/src/vec/columns/column.h
@@ -750,6 +750,11 @@ protected:
             static_cast<Derived&>(*this).insert_from(*srcs[i], positions[i]);
         }
     }
+
+    // Used to check nested const occurrences; const is only allowed at the 
top level.
+    // e.g. const(nullable(...)) is allowed.
+    // const(array(const(...))) is not allowed.
+    void check_const_only_in_top_level() const;
 };
 
 using ColumnPtr = IColumn::Ptr;
diff --git a/be/src/vec/columns/column_array.cpp 
b/be/src/vec/columns/column_array.cpp
index 58457ca406f..a3e6ebe3a6b 100644
--- a/be/src/vec/columns/column_array.cpp
+++ b/be/src/vec/columns/column_array.cpp
@@ -62,9 +62,7 @@ ColumnArray::ColumnArray(MutableColumnPtr&& nested_column, 
MutableColumnPtr&& of
     //                                "nested_column must be nullable, but got 
{}", data->get_name());
     //     }
     // #endif
-
-    data = data->convert_to_full_column_if_const();
-    offsets = offsets->convert_to_full_column_if_const();
+    check_const_only_in_top_level();
     const auto* offsets_concrete = typeid_cast<const 
ColumnOffsets*>(offsets.get());
 
     if (!offsets_concrete) {
diff --git a/be/src/vec/columns/column_map.cpp 
b/be/src/vec/columns/column_map.cpp
index 3e93a6185bc..88f811dffcb 100644
--- a/be/src/vec/columns/column_map.cpp
+++ b/be/src/vec/columns/column_map.cpp
@@ -52,6 +52,7 @@ ColumnMap::ColumnMap(MutableColumnPtr&& keys, 
MutableColumnPtr&& values, Mutable
         : keys_column(std::move(keys)),
           values_column(std::move(values)),
           offsets_column(std::move(offsets)) {
+    check_const_only_in_top_level();
     const auto* offsets_concrete = assert_cast<const 
COffsets*>(offsets_column.get());
 
     if (!offsets_concrete->empty() && keys_column && values_column) {
diff --git a/be/src/vec/columns/column_nullable.cpp 
b/be/src/vec/columns/column_nullable.cpp
index f0cf6943c09..bb9e7914ff9 100644
--- a/be/src/vec/columns/column_nullable.cpp
+++ b/be/src/vec/columns/column_nullable.cpp
@@ -32,9 +32,7 @@ namespace doris::vectorized {
 
 ColumnNullable::ColumnNullable(MutableColumnPtr&& nested_column_, 
MutableColumnPtr&& null_map_)
         : _nested_column(std::move(nested_column_)), 
_null_map(std::move(null_map_)) {
-    /// ColumnNullable cannot have constant nested column. But constant 
argument could be passed. Materialize it.
-    _nested_column = get_nested_column().convert_to_full_column_if_const();
-
+    check_const_only_in_top_level();
     // after convert const column to full column, it may be a nullable column
     if (_nested_column->is_nullable()) {
         assert_cast<ColumnNullable&>(*_nested_column)
diff --git a/be/src/vec/columns/column_struct.cpp 
b/be/src/vec/columns/column_struct.cpp
index 1d0cb9302e0..ca908fc9605 100644
--- a/be/src/vec/columns/column_struct.cpp
+++ b/be/src/vec/columns/column_struct.cpp
@@ -62,6 +62,7 @@ ColumnStruct::ColumnStruct(MutableColumns&& mutable_columns) {
         }
         columns.push_back(std::move(column));
     }
+    check_const_only_in_top_level();
 }
 
 ColumnStruct::MutablePtr ColumnStruct::create(const Columns& columns) {
diff --git a/be/test/vec/columns/column_array_test.cpp 
b/be/test/vec/columns/column_array_test.cpp
index bbac856bd88..08224b55d6e 100644
--- a/be/test/vec/columns/column_array_test.cpp
+++ b/be/test/vec/columns/column_array_test.cpp
@@ -612,60 +612,57 @@ TEST_F(ColumnArrayTest, ShrinkPaddingCharsTest) {
 
 //////////////////////// special function from column_array.h 
////////////////////////
 TEST_F(ColumnArrayTest, CreateArrayTest) {
-    // test create_array : nested_column && offsets_column should not be 
const, and convert_to_full_column_if_const should not impl in array
-    // in some situation,
-    //  like join_probe_operator.cpp::_build_output_block,
-    //  we call column.convert_to_full_column_if_const,
-    //  then we may call clear_column_data() to clear the column (eg. in 
HashJoinProbeOperatorX::pull() which call 
local_state._probe_block.clear_column_data after filter_data_and_build_output())
-    //  in clear_column_data() if use_count() == 1, we will call 
column->clear() to clear the column data
-    //
-    //  however in array impl for convert_to_full_column_if_const: ``` 
ColumnArray::create(data->convert_to_full_column_if_const(), offsets);```
-    //  may make the nested_column use_count() more than 1 which means it is 
shared with other block, but return ColumnArray is new which use_count() is 1,
-    //  then in clear_column_data() if we will call array_column->use_count() 
== 1 will be true to clear the column with nested_column, and shared 
nested_column block will meet undefined behavior cause maybe core
-    //
-    //  so actually according to the semantics of the function, it should not 
impl in array,
-    //  but we should make sure in creation of array, the nested_column && 
offsets_column should not be const
+    // Test ColumnArray constructor constraints: nested_column and 
offsets_column must not be ColumnConst.
+    // The constructor enforces this via check_const_only_in_top_level(), 
preventing COW-related issues:
+    // - ColumnConst is immutable and meant for repeated values across rows
+    // - ColumnArray requires mutable nested data for operations like 
insert/filter/clear
+    // - Wrapping shared ColumnConst in ColumnArray violates use_count() 
assumptions in clear_column_data()
     for (auto& array_column : array_columns) {
         const auto* column = check_and_get_column<ColumnArray>(
                 remove_nullable(array_column->assume_mutable()).get());
         auto column_size = column->size();
         LOG(INFO) << "column_type: " << column->get_name();
-        // test create_array
-        // test create expect exception case
-        // 1.offsets is not ColumnOffset64
-        auto tmp_data_col = column->get_data_ptr()->clone_resized(1);
-        MutableColumnPtr tmp_offsets_col =
-                assert_cast<const 
ColumnArray::ColumnOffsets&>(column->get_offsets_column())
-                        .clone_resized(1);
-        // 2.offsets size is not equal to data size
+
+        // Test expected exception cases
+        // 1. nested_column is ColumnConst (violates 
check_const_only_in_top_level)
+        auto tmp_data_col = column->get_data_ptr()->clone_empty();
+        tmp_data_col->insert_default(); // ColumnConst requires nested column 
size = 1
+        auto const_data = ColumnConst::create(std::move(tmp_data_col), 
column_size);
+        EXPECT_ANY_THROW({
+            auto new_array_column =
+                    ColumnArray::create(const_data->assume_mutable(), 
column->get_offsets_ptr());
+        });
+
+        // 2. offsets_column is ColumnConst (violates 
check_const_only_in_top_level)
+        auto tmp_offsets_col = column->get_offsets_ptr()->clone_empty();
+        tmp_offsets_col->insert_default(); // ColumnConst requires nested 
column size = 1
+        auto const_offsets = ColumnConst::create(std::move(tmp_offsets_col), 
column_size);
+        EXPECT_ANY_THROW({
+            auto new_array_column =
+                    ColumnArray::create(column->get_data_ptr(), 
const_offsets->assume_mutable());
+        });
+
+        // 3. offsets size does not match data size
         auto tmp_data_col1 = column->get_data_ptr()->clone_resized(2);
         EXPECT_ANY_THROW({
             auto new_array_column = ColumnArray::create(
                     tmp_data_col1->assume_mutable(),
                     
column->get_offsets_column().clone_resized(1)->assume_mutable());
         });
-        // 3.data is const
-        auto last_offset = column->get_offsets().back();
-        EXPECT_ANY_THROW(
-                { auto const_col = ColumnConst::create(column->get_data_ptr(), 
last_offset); });
-        Field assert_field;
-        column->get(0, assert_field);
-        auto const_col = ColumnConst::create(tmp_data_col->assume_mutable(), 
last_offset);
-        EXPECT_ANY_THROW({
-            // const_col is not empty
-            auto new_array_column = 
ColumnArray::create(const_col->assume_mutable());
-        });
+
+        // Test successful creation with normal columns
         auto new_array_column =
-                ColumnArray::create(const_col->assume_mutable(), 
column->get_offsets_ptr());
-        EXPECT_EQ(new_array_column->size(), column_size)
-                << "array_column size is not equal to column size";
+                ColumnArray::create(column->get_data_ptr(), 
column->get_offsets_ptr());
+        EXPECT_EQ(new_array_column->size(), column_size);
         EXPECT_EQ(new_array_column->get_data_ptr()->size(), 
column->get_data_ptr()->size());
         EXPECT_EQ(new_array_column->get_offsets_ptr()->size(), 
column->get_offsets_ptr()->size());
-        // check column data
+
+        // Verify data integrity
         for (size_t j = 0; j < column_size; j++) {
-            Field f1;
+            Field f1, f2;
             new_array_column->get(j, f1);
-            EXPECT_EQ(f1, assert_field) << "array_column data is not equal to 
column data";
+            column->get(j, f2);
+            EXPECT_EQ(f1, f2);
         }
     }
 }
diff --git a/be/test/vec/columns/column_check_const_only_in_top_level_test.cpp 
b/be/test/vec/columns/column_check_const_only_in_top_level_test.cpp
new file mode 100644
index 00000000000..6a52f6fadcc
--- /dev/null
+++ b/be/test/vec/columns/column_check_const_only_in_top_level_test.cpp
@@ -0,0 +1,311 @@
+// 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
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gtest/gtest.h>
+
+#include "testutil/column_helper.h"
+#include "vec/columns/column.h"
+#include "vec/columns/column_array.h"
+#include "vec/columns/column_const.h"
+#include "vec/columns/column_map.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/columns/column_struct.h"
+#include "vec/columns/column_vector.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/data_types/data_type_map.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/data_types/data_type_struct.h"
+
+namespace doris::vectorized {
+
+class ColumnCheckConstOnlyInTopLevelTest : public ::testing::Test {
+protected:
+    void SetUp() override {}
+    void TearDown() override {}
+};
+
+// Test ColumnNullable: nested column should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnNullableWithConstNested) {
+    // Create a const column (nested column size must be 1 when 
create_with_empty=false)
+    auto int_col = ColumnHelper::create_column<DataTypeInt32>({1});
+    auto const_col = ColumnConst::create(int_col, 3, false, false);
+
+    // Create a null map
+    auto null_map = ColumnUInt8::create();
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+
+    // Try to create ColumnNullable with const nested column - should throw
+    EXPECT_THROW({ ColumnNullable::create(std::move(const_col), 
std::move(null_map)); },
+                 doris::Exception);
+}
+
+// Test ColumnNullable: normal case (non-const nested column) should not throw
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnNullableWithNonConstNested) {
+    auto int_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto null_map = ColumnUInt8::create();
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+
+    // Should not throw
+    EXPECT_NO_THROW({
+        auto nullable_col = ColumnNullable::create(std::move(int_col), 
std::move(null_map));
+        EXPECT_EQ(nullable_col->size(), 3);
+    });
+}
+
+// Test ColumnArray: nested data column should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnArrayWithConstData) {
+    // Create a const column (nested column size must be 1 when 
create_with_empty=false)
+    auto int_col = ColumnHelper::create_column<DataTypeInt32>({1});
+    auto const_col = ColumnConst::create(int_col, 3, false, false);
+
+    // Create offsets
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+
+    // Try to create ColumnArray with const data column - should throw
+    EXPECT_THROW({ ColumnArray::create(std::move(const_col), 
std::move(offsets)); },
+                 doris::Exception);
+}
+
+// Test ColumnArray: normal case should not throw
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnArrayWithNonConstData) {
+    auto int_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+
+    // Should not throw
+    EXPECT_NO_THROW({
+        auto array_col = ColumnArray::create(std::move(int_col), 
std::move(offsets));
+        EXPECT_EQ(array_col->size(), 1);
+    });
+}
+
+// Test ColumnStruct: nested columns should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnStructWithConstElement) {
+    // Create a const column (nested column size must be 1 when 
create_with_empty=false)
+    auto int_col = ColumnHelper::create_column<DataTypeInt32>({1});
+    auto const_col = ColumnConst::create(int_col, 3, false, false);
+
+    MutableColumns columns;
+    columns.push_back(std::move(const_col));
+
+    // Try to create ColumnStruct with const element - should throw
+    EXPECT_THROW({ ColumnStruct::create(std::move(columns)); }, 
doris::Exception);
+}
+
+// Test ColumnStruct: normal case should not throw
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnStructWithNonConstElements) {
+    auto int_col1 = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto int_col2 = ColumnHelper::create_column<DataTypeInt32>({4, 5, 6});
+
+    MutableColumns columns;
+    columns.push_back(int_col1->assume_mutable());
+    columns.push_back(int_col2->assume_mutable());
+
+    // Should not throw
+    EXPECT_NO_THROW({
+        auto struct_col = ColumnStruct::create(std::move(columns));
+        EXPECT_EQ(struct_col->size(), 3);
+    });
+}
+
+// Test ColumnMap: keys column should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnMapWithConstKeys) {
+    // Create a const keys column (nested column size must be 1 when 
create_with_empty=false)
+    auto keys_col = ColumnHelper::create_column<DataTypeInt32>({1});
+    auto const_keys = ColumnConst::create(keys_col, 3, false, false);
+
+    // Create normal values column
+    auto values_col = ColumnHelper::create_column<DataTypeInt32>({10, 20, 30});
+
+    // Create offsets
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+
+    // Try to create ColumnMap with const keys - should throw
+    EXPECT_THROW(
+            {
+                ColumnMap::create(std::move(const_keys), 
std::move(values_col), std::move(offsets));
+            },
+            doris::Exception);
+}
+
+// Test ColumnMap: values column should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnMapWithConstValues) {
+    // Create normal keys column
+    auto keys_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+
+    // Create a const values column (nested column size must be 1 when 
create_with_empty=false)
+    auto values_col = ColumnHelper::create_column<DataTypeInt32>({10});
+    auto const_values = ColumnConst::create(values_col, 3, false, false);
+
+    // Create offsets
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+
+    // Try to create ColumnMap with const values - should throw
+    EXPECT_THROW(
+            {
+                ColumnMap::create(std::move(keys_col), 
std::move(const_values), std::move(offsets));
+            },
+            doris::Exception);
+}
+
+// Test ColumnMap: offsets column should not be const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnMapWithConstOffsets) {
+    // Create normal keys and values columns
+    auto keys_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto values_col = ColumnHelper::create_column<DataTypeInt32>({10, 20, 30});
+
+    // Create a const offsets column (nested column size must be 1 when 
create_with_empty=false)
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+    auto const_offsets = ColumnConst::create(std::move(offsets), 1, false, 
false);
+
+    // Try to create ColumnMap with const offsets - should throw
+    EXPECT_THROW(
+            {
+                ColumnMap::create(std::move(keys_col), std::move(values_col),
+                                  std::move(const_offsets));
+            },
+            doris::Exception);
+}
+
+// Test ColumnMap: normal case should not throw
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, ColumnMapWithNonConstColumns) {
+    auto keys_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto values_col = ColumnHelper::create_column<DataTypeInt32>({10, 20, 30});
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+
+    // Should not throw
+    EXPECT_NO_THROW({
+        auto map_col =
+                ColumnMap::create(std::move(keys_col), std::move(values_col), 
std::move(offsets));
+        EXPECT_EQ(map_col->size(), 1);
+    });
+}
+
+// Test deeply nested const column - Array<Array<Int32>> with inner array 
being const
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, NestedArrayWithConstInnerArray) {
+    // Create an inner array column (size 1 for const creation)
+    auto inner_data = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto inner_offsets = ColumnArray::ColumnOffsets::create();
+    inner_offsets->insert_value(3);
+    auto inner_array = ColumnArray::create(std::move(inner_data), 
std::move(inner_offsets));
+
+    // Make the inner array const (nested column size must be 1 when 
create_with_empty=false)
+    auto const_inner_array = ColumnConst::create(std::move(inner_array), 2, 
false, false);
+
+    // Try to create outer array with const inner array - should throw
+    auto outer_offsets = ColumnArray::ColumnOffsets::create();
+    outer_offsets->insert_value(2);
+
+    EXPECT_THROW({ ColumnArray::create(std::move(const_inner_array), 
std::move(outer_offsets)); },
+                 doris::Exception);
+}
+
+// Test Nullable<Array<Int32>> with const array nested
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, NullableWithConstArray) {
+    // Create an array column (size 1 for const creation)
+    auto data = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+    auto array_col = ColumnArray::create(std::move(data), std::move(offsets));
+
+    // Make the array const (nested column size must be 1 when 
create_with_empty=false)
+    auto const_array = ColumnConst::create(std::move(array_col), 3, false, 
false);
+
+    // Create null map
+    auto null_map = ColumnUInt8::create();
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+    null_map->insert_value(0);
+
+    // Try to create ColumnNullable with const array nested - should throw
+    EXPECT_THROW({ ColumnNullable::create(std::move(const_array), 
std::move(null_map)); },
+                 doris::Exception);
+}
+
+// Test Struct<Array<Int32>> with const array element
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, StructWithConstArrayElement) {
+    // Create an array column (size 1 for const creation)
+    auto data = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+    auto offsets = ColumnArray::ColumnOffsets::create();
+    offsets->insert_value(3);
+    auto array_col = ColumnArray::create(std::move(data), std::move(offsets));
+
+    // Make the array const (nested column size must be 1 when 
create_with_empty=false)
+    auto const_array = ColumnConst::create(std::move(array_col), 3, false, 
false);
+
+    MutableColumns columns;
+    columns.push_back(std::move(const_array));
+
+    // Try to create ColumnStruct with const array element - should throw
+    EXPECT_THROW({ ColumnStruct::create(std::move(columns)); }, 
doris::Exception);
+}
+
+// Test check_const_only_in_top_level directly
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, DirectCheckConstOnlyInTopLevel) {
+    // Normal column should not throw
+    {
+        auto int_col = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+        EXPECT_NO_THROW({ int_col->check_const_only_in_top_level(); });
+    }
+
+    // Normal nullable column should not throw
+    {
+        auto nullable_col =
+                ColumnHelper::create_nullable_column<DataTypeInt32>({1, 2, 3}, 
{0, 0, 0});
+        EXPECT_NO_THROW({ nullable_col->check_const_only_in_top_level(); });
+    }
+
+    // Normal array column should not throw
+    {
+        auto data = ColumnHelper::create_column<DataTypeInt32>({1, 2, 3});
+        auto offsets = ColumnArray::ColumnOffsets::create();
+        offsets->insert_value(3);
+        auto array_col = ColumnArray::create(std::move(data), 
std::move(offsets));
+        EXPECT_NO_THROW({ array_col->check_const_only_in_top_level(); });
+    }
+}
+
+// Test empty columns
+TEST_F(ColumnCheckConstOnlyInTopLevelTest, EmptyColumnsNoThrow) {
+    // Empty array should not throw
+    {
+        auto data = ColumnHelper::create_column<DataTypeInt32>({});
+        auto array_col = ColumnArray::create(std::move(data));
+        EXPECT_NO_THROW({ array_col->check_const_only_in_top_level(); });
+    }
+
+    // Empty map should not throw
+    {
+        auto keys = ColumnHelper::create_column<DataTypeInt32>({});
+        auto values = ColumnHelper::create_column<DataTypeInt32>({});
+        auto offsets = ColumnArray::ColumnOffsets::create();
+        auto map_col = ColumnMap::create(std::move(keys), std::move(values), 
std::move(offsets));
+        EXPECT_NO_THROW({ map_col->check_const_only_in_top_level(); });
+    }
+}
+
+} // namespace doris::vectorized


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

Reply via email to