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

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new e4131f9aee6 branch-3.1: [fix](variant)fix variant type conflicts in 
nested types #52696 (#53119)
e4131f9aee6 is described below

commit e4131f9aee61e5cd8e96abf05a6b95cb51cab1f2
Author: amory <[email protected]>
AuthorDate: Fri Jul 25 17:36:39 2025 +0800

    branch-3.1: [fix](variant)fix variant type conflicts in nested types #52696 
(#53119)
    
    picked from #52696
---
 be/src/vec/columns/column_object.cpp               |   6 -
 be/src/vec/columns/column_object.h                 |   1 +
 be/src/vec/data_types/convert_field_to_type.cpp    |   2 +-
 be/src/vec/json/json_parser.cpp                    |  12 +-
 be/src/vec/json/json_parser.h                      |   2 +
 .../vec/columns/column_variant_allocated_bytes.out | Bin 53 -> 49 bytes
 .../vec/columns/column_variant_byte_size.out       | Bin 49 -> 41 bytes
 .../column_variant_update_crc_with_value.out       | Bin 53 -> 52 bytes
 ..._variant_update_crc_with_value_with_nullmap.out | Bin 53 -> 52 bytes
 .../column_variant_update_crcs_with_value.out      | Bin 21667 -> 195 bytes
 ...variant_update_crcs_with_value_with_nullmap.out | Bin 21667 -> 195 bytes
 .../column_variant_update_hashes_with_value.out    | Bin 41224 -> 330 bytes
 ...riant_update_hashes_with_value_with_nullmap.out | Bin 41224 -> 330 bytes
 .../column_variant_update_xxHash_with_value.out    | Bin 63 -> 62 bytes
 ...riant_update_xxHash_with_value_with_nullmap.out | Bin 63 -> 62 bytes
 be/test/vec/columns/column_object_test.cpp         |  15 +-
 be/test/vec/columns/column_variant_test.cpp        |  60 +--
 .../function/cast/function_variant_cast_test.cpp   | 466 ++++++++++++++++++
 be/test/vec/jsonb/convert_field_to_type_test.cpp   | 521 +++++++++++++++++++++
 be/test/vec/jsonb/json_parser_test.cpp             | 169 +++++++
 regression-test/data/variant_p0/desc.out           | Bin 5887 -> 5908 bytes
 regression-test/data/variant_p0/load.out           | Bin 16310 -> 16319 bytes
 regression-test/data/variant_p0/nested2.out        | Bin 0 -> 3467 bytes
 regression-test/suites/variant_p0/nested2.groovy   | 151 ++++++
 24 files changed, 1344 insertions(+), 61 deletions(-)

diff --git a/be/src/vec/columns/column_object.cpp 
b/be/src/vec/columns/column_object.cpp
index 01bddae0016..f825be48f80 100644
--- a/be/src/vec/columns/column_object.cpp
+++ b/be/src/vec/columns/column_object.cpp
@@ -87,12 +87,6 @@ DataTypePtr create_array_of_type(TypeIndex type, size_t 
num_dimensions, bool is_
     if (type == TypeIndex::Nothing) {
         return std::make_shared<DataTypeNothing>();
     }
-    if (type == ColumnObject::MOST_COMMON_TYPE_ID) {
-        // JSONB type MUST NOT wrapped in ARRAY column, it should be top level.
-        // So we ignored num_dimensions.
-        return is_nullable ? 
make_nullable(std::make_shared<ColumnObject::MostCommonType>())
-                           : std::make_shared<ColumnObject::MostCommonType>();
-    }
     DataTypePtr result =
             DataTypeFactory::instance().create_data_type(type, is_nullable, 
precision, scale);
     for (size_t i = 0; i < num_dimensions; ++i) {
diff --git a/be/src/vec/columns/column_object.h 
b/be/src/vec/columns/column_object.h
index 971537c6155..319e5569e95 100644
--- a/be/src/vec/columns/column_object.h
+++ b/be/src/vec/columns/column_object.h
@@ -114,6 +114,7 @@ public:
     constexpr static TypeIndex MOST_COMMON_TYPE_ID = TypeIndex::JSONB;
     // Nullable(Array(Nullable(Object)))
     const static DataTypePtr NESTED_TYPE;
+
     // 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.
diff --git a/be/src/vec/data_types/convert_field_to_type.cpp 
b/be/src/vec/data_types/convert_field_to_type.cpp
index ca8984b313d..5a50b446b9b 100644
--- a/be/src/vec/data_types/convert_field_to_type.cpp
+++ b/be/src/vec/data_types/convert_field_to_type.cpp
@@ -335,4 +335,4 @@ void convert_field_to_type(const Field& from_value, const 
IDataType& to_type, Fi
         return convert_field_to_typeImpl(from_value, to_type, from_type_hint, 
to);
     }
 }
-} // namespace doris::vectorized
\ No newline at end of file
+} // namespace doris::vectorized
diff --git a/be/src/vec/json/json_parser.cpp b/be/src/vec/json/json_parser.cpp
index f6e8a65cc08..e031f168820 100644
--- a/be/src/vec/json/json_parser.cpp
+++ b/be/src/vec/json/json_parser.cpp
@@ -59,8 +59,14 @@ void JSONDataParser<ParserImpl>::traverse(const Element& 
element, ParseContext&
     if (element.isObject()) {
         traverseObject(element.getObject(), ctx);
     } else if (element.isArray()) {
+        if (ctx.has_nested_in_flatten) {
+            throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT,
+                                   "Nesting of array in Nested array within 
variant subcolumns is "
+                                   "currently not supported.");
+        }
         has_nested = false;
         check_has_nested_object(element);
+        ctx.has_nested_in_flatten = has_nested && ctx.enable_flatten_nested;
         if (has_nested && !ctx.enable_flatten_nested) {
             // Parse nested arrays to JsonbField
             JsonbWriter writer;
@@ -71,6 +77,8 @@ void JSONDataParser<ParserImpl>::traverse(const Element& 
element, ParseContext&
         } else {
             traverseArray(element.getArray(), ctx);
         }
+        // we should set has_nested_in_flatten to false when traverse array 
finished for next array otherwise it will be true for next array
+        ctx.has_nested_in_flatten = false;
     } else {
         ctx.paths.push_back(ctx.builder.get_parts());
         ctx.values.push_back(getValueAsField(element));
@@ -137,6 +145,7 @@ template <typename ParserImpl>
 void JSONDataParser<ParserImpl>::traverseArray(const JSONArray& array, 
ParseContext& ctx) {
     /// Traverse elements of array and collect an array of fields by each path.
     ParseArrayContext array_ctx;
+    array_ctx.has_nested_in_flatten = ctx.has_nested_in_flatten;
     array_ctx.total_size = array.size();
     for (auto it = array.begin(); it != array.end(); ++it) {
         traverseArrayElement(*it, array_ctx);
@@ -162,8 +171,9 @@ template <typename ParserImpl>
 void JSONDataParser<ParserImpl>::traverseArrayElement(const Element& element,
                                                       ParseArrayContext& ctx) {
     ParseContext element_ctx;
+    element_ctx.has_nested_in_flatten = ctx.has_nested_in_flatten;
     traverse(element, element_ctx);
-    auto& [_, paths, values, flatten_nested] = element_ctx;
+    auto& [_, paths, values, flatten_nested, has_nested] = element_ctx;
     size_t size = paths.size();
     size_t keys_to_update = ctx.arrays_by_path.size();
     for (size_t i = 0; i < size; ++i) {
diff --git a/be/src/vec/json/json_parser.h b/be/src/vec/json/json_parser.h
index 52336d455c0..8d47e1936fd 100644
--- a/be/src/vec/json/json_parser.h
+++ b/be/src/vec/json/json_parser.h
@@ -145,6 +145,7 @@ private:
         std::vector<PathInData::Parts> paths;
         std::vector<Field> values;
         bool enable_flatten_nested = false;
+        bool has_nested_in_flatten = false;
     };
     using PathPartsWithArray = std::pair<PathInData::Parts, Array>;
     using PathToArray = phmap::flat_hash_map<UInt128, PathPartsWithArray, 
UInt128TrivialHash>;
@@ -154,6 +155,7 @@ private:
         size_t total_size = 0;
         PathToArray arrays_by_path;
         KeyToSizes nested_sizes_by_key;
+        bool has_nested_in_flatten = false;
     };
     void traverse(const Element& element, ParseContext& ctx);
     void traverseObject(const JSONObject& object, ParseContext& ctx);
diff --git 
a/be/test/expected_result/vec/columns/column_variant_allocated_bytes.out 
b/be/test/expected_result/vec/columns/column_variant_allocated_bytes.out
index 346c07705ac..3aec885b6b8 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_allocated_bytes.out and 
b/be/test/expected_result/vec/columns/column_variant_allocated_bytes.out differ
diff --git a/be/test/expected_result/vec/columns/column_variant_byte_size.out 
b/be/test/expected_result/vec/columns/column_variant_byte_size.out
index 54e7a490f26..85e0a0b6fb5 100644
Binary files a/be/test/expected_result/vec/columns/column_variant_byte_size.out 
and b/be/test/expected_result/vec/columns/column_variant_byte_size.out differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_crc_with_value.out 
b/be/test/expected_result/vec/columns/column_variant_update_crc_with_value.out
index b2e93e82ac0..26218ea29a0 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_crc_with_value.out 
and 
b/be/test/expected_result/vec/columns/column_variant_update_crc_with_value.out 
differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_crc_with_value_with_nullmap.out
 
b/be/test/expected_result/vec/columns/column_variant_update_crc_with_value_with_nullmap.out
index b2e93e82ac0..26218ea29a0 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_crc_with_value_with_nullmap.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_crc_with_value_with_nullmap.out
 differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value.out 
b/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value.out
index 6a347c4861a..18beb2922b8 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value.out 
and 
b/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value.out 
differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value_with_nullmap.out
 
b/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value_with_nullmap.out
index 6a347c4861a..18beb2922b8 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value_with_nullmap.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_crcs_with_value_with_nullmap.out
 differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value.out
 
b/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value.out
index 94ed6fb2fd6..1675df9272e 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value.out
 differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value_with_nullmap.out
 
b/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value_with_nullmap.out
index 94ed6fb2fd6..1675df9272e 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value_with_nullmap.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_hashes_with_value_with_nullmap.out
 differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value.out
 
b/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value.out
index 80c79e48777..a47b1bf2981 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value.out
 differ
diff --git 
a/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value_with_nullmap.out
 
b/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value_with_nullmap.out
index 80c79e48777..a47b1bf2981 100644
Binary files 
a/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value_with_nullmap.out
 and 
b/be/test/expected_result/vec/columns/column_variant_update_xxHash_with_value_with_nullmap.out
 differ
diff --git a/be/test/vec/columns/column_object_test.cpp 
b/be/test/vec/columns/column_object_test.cpp
index 7d10b5e77ef..25a41722f95 100644
--- a/be/test/vec/columns/column_object_test.cpp
+++ b/be/test/vec/columns/column_object_test.cpp
@@ -634,10 +634,17 @@ TEST(ColumnVariantTest, advanced_insert_range_from) {
             }
         } else if (column->path.get_path().size() == 5) {
             EXPECT_EQ(column->data.get_non_null_value_size(), 10);
-            EXPECT_EQ(assert_cast<const 
DataTypeNullable*>(column->data.data_types[0].get())
-                              ->get_nested_type()
-                              ->get_type_id(),
-                      TypeIndex::JSONB);
+            if (column->path.get_path() == "v.d.d") {
+                EXPECT_EQ(assert_cast<const 
DataTypeNullable*>(column->data.data_types[0].get())
+                                  ->get_nested_type()
+                                  ->get_type_id(),
+                          TypeIndex::Array);
+            } else if (column->path.get_path() == "v.c.d") {
+                EXPECT_EQ(assert_cast<const 
DataTypeNullable*>(column->data.data_types[0].get())
+                                  ->get_nested_type()
+                                  ->get_type_id(),
+                          TypeIndex::JSONB);
+            }
             for (size_t row = 0; row < 5; ++row) {
                 EXPECT_TRUE(column->data.data[0]->is_null_at(row));
             }
diff --git a/be/test/vec/columns/column_variant_test.cpp 
b/be/test/vec/columns/column_variant_test.cpp
index a7fba428b37..d6f35a50bb1 100644
--- a/be/test/vec/columns/column_variant_test.cpp
+++ b/be/test/vec/columns/column_variant_test.cpp
@@ -49,15 +49,14 @@ static ColumnObject::MutablePtr column_variant;
 class ColumnObjectTest : public CommonColumnTest {
 protected:
     static void SetUpTestSuite() {
-        root_dir = std::string(getenv("ROOT"));
+        column_variant = VariantUtil::construct_advanced_varint_column();
+        std::cout << column_variant->get_name() << std::endl;
+        root_dir = std::string(getenv("DORIS_HOME"));
+        // which is /root/doris/be/ut_build_ASAN/test//
         std::cout << "root_dir: " << root_dir << std::endl;
-        test_data_dir = root_dir + "/be/test/data/vec/columns";
-        test_result_dir = root_dir + "/be/test/expected_result/vec/columns";
-
-        column_variant = ColumnObject::create(true);
-        std::cout << dt_variant->get_name() << std::endl;
-
-        load_json_columns_data();
+        test_data_dir = root_dir + "../../../be/test/data/vec/columns";
+        test_result_dir = root_dir + 
"../../../be/test/expected_result/vec/columns";
+        //load_json_columns_data();
     }
 
     static void load_json_columns_data() {
@@ -220,11 +219,7 @@ TEST_F(ColumnObjectTest, field_test) {
         }
     };
     ColumnObject::MutablePtr obj;
-    obj = ColumnObject::create(1);
-    MutableColumns cols;
-    cols.push_back(obj->get_ptr());
-    const auto& json_file_obj = test_data_dir_json + 
"json_variant/object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_obj);
+    obj = VariantUtil::construct_advanced_varint_column();
     EXPECT_TRUE(!obj->empty());
     test_func(obj);
 }
@@ -750,11 +745,7 @@ TEST_F(ColumnObjectTest, get_subcolumn) {
 
 TEST_F(ColumnObjectTest, ensure_root_node_type) {
     ColumnObject::MutablePtr obj;
-    obj = ColumnObject::create(1);
-    MutableColumns cols;
-    cols.push_back(obj->get_ptr());
-    const auto& json_file_obj = test_data_dir_json + 
"json_variant/object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_obj);
+    obj = VariantUtil::construct_advanced_varint_column();
     EXPECT_TRUE(!obj->empty());
     // Store original root type
     auto root = obj->get_subcolumns().get_root();
@@ -1188,11 +1179,7 @@ TEST_F(ColumnObjectTest, 
find_path_lower_bound_in_sparse_data) {
         }
     };
     ColumnObject::MutablePtr obj;
-    obj = ColumnObject::create(1);
-    MutableColumns cols;
-    cols.push_back(obj->get_ptr());
-    const auto& json_file_obj = test_data_dir_json + 
"json_variant/object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_obj);
+    obj = VariantUtil::construct_advanced_varint_column();
     EXPECT_TRUE(!obj->empty());
     std::cout << "column variant size: " << obj->size() << std::endl;
     test_func(obj);
@@ -1201,11 +1188,7 @@ TEST_F(ColumnObjectTest, 
find_path_lower_bound_in_sparse_data) {
 // used in SparseColumnExtractIterator::_fill_path_column
 TEST_F(ColumnObjectTest, fill_path_column_from_sparse_data) {
     ColumnObject::MutablePtr obj;
-    obj = ColumnObject::create(1);
-    MutableColumns cols;
-    cols.push_back(obj->get_ptr());
-    const auto& json_file_obj = test_data_dir_json + 
"json_variant/object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_obj);
+    obj = VariantUtil::construct_advanced_varint_column();
     EXPECT_TRUE(!obj->empty());
     auto sparse_col = obj->get_sparse_column();
     auto cloned_sparse = sparse_col->clone_empty();
@@ -1226,27 +1209,6 @@ TEST_F(ColumnObjectTest, 
fill_path_column_from_sparse_data) {
     EXPECT_ANY_THROW(obj->check_consistency());
 }
 
-TEST_F(ColumnObjectTest, not_finalized) {
-    ColumnObject::MutablePtr obj;
-    obj = ColumnObject::create(1);
-    MutableColumns cols;
-    cols.push_back(obj->get_ptr());
-    const auto& json_file_obj = test_data_dir_json + 
"json_variant/object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_obj);
-    const auto& json_file_arr = test_data_dir_json + 
"json_variant/array_object_boundary.jsonl";
-    load_columns_data_from_file(cols, serde, '\n', {0}, json_file_arr);
-    EXPECT_TRUE(obj->size() == 200);
-    EXPECT_FALSE(obj->is_finalized());
-    // test get_finalized_column_ptr/ get_finalized_column for subColumn
-    auto subcolumns = obj->get_subcolumns();
-    for (const auto& subcolumn : subcolumns) {
-        EXPECT_TRUE(subcolumn != nullptr);
-        EXPECT_FALSE(subcolumn->data.is_finalized());
-        EXPECT_ANY_THROW(subcolumn->data.get_finalized_column_ptr());
-        EXPECT_ANY_THROW(subcolumn->data.get_finalized_column());
-    }
-}
-
 doris::vectorized::Field get_field_v2(std::string_view type, size_t 
array_element_cnt = 0) {
     static std::unordered_map<std::string_view, doris::vectorized::Field> 
field_map;
     if (field_map.empty()) {
diff --git a/be/test/vec/function/cast/function_variant_cast_test.cpp 
b/be/test/vec/function/cast/function_variant_cast_test.cpp
new file mode 100644
index 00000000000..aa026d4a155
--- /dev/null
+++ b/be/test/vec/function/cast/function_variant_cast_test.cpp
@@ -0,0 +1,466 @@
+// 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 <vector>
+
+#include "common/status.h"
+#include "gtest/gtest_pred_impl.h"
+#include "olap/field.h"
+#include "runtime/define_primitive_type.h"
+#include "runtime/primitive_type.h"
+#include "runtime/runtime_state.h"
+#include "vec/columns/column_array.h"
+#include "vec/columns/column_object.h"
+#include "vec/core/field.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/data_types/data_type_object.h"
+#include "vec/data_types/data_type_string.h"
+#include "vec/functions/simple_function_factory.h"
+
+namespace doris::vectorized {
+static doris::vectorized::Field construct_variant_map(
+        const std::vector<std::pair<std::string, doris::vectorized::Field>>& 
key_and_values) {
+    doris::vectorized::Field res = VariantMap();
+    auto& object = res.get<VariantMap&>();
+    for (const auto& [k, v] : key_and_values) {
+        PathInData path(k);
+        object.try_emplace(path, v);
+    }
+    return res;
+}
+
+static auto construct_basic_varint_column() {
+    // 1. create an empty variant column
+    auto variant = ColumnObject::create(5);
+
+    std::vector<std::pair<std::string, doris::vectorized::Field>> data;
+
+    // 2. subcolumn path
+    data.emplace_back("v.a", 20);
+    data.emplace_back("v.b", "20");
+    data.emplace_back("v.c", 20);
+    data.emplace_back("v.f", 20);
+    data.emplace_back("v.e", "50");
+    for (int i = 0; i < 5; ++i) {
+        auto field = construct_variant_map(data);
+        variant->try_insert(field);
+    }
+
+    return variant;
+}
+
+TEST(FunctionVariantCast, CastToVariant) {
+    // Test casting from basic types to variant
+    {
+        // Test Int32 to variant
+        auto int32_type = std::make_shared<DataTypeInt32>();
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto int32_col = ColumnInt32::create();
+        int32_col->insert(42);
+        int32_col->insert(100);
+        int32_col->insert(-1);
+
+        ColumnsWithTypeAndName arguments {{int32_col->get_ptr(), int32_type, 
"int32_col"},
+                                          {nullptr, variant_type, 
"variant_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, variant_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, variant_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
3).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* variant_col = assert_cast<const 
ColumnObject*>(result_col.get());
+        ASSERT_EQ(variant_col->size(), 3);
+    }
+
+    // Test casting from string to variant
+    {
+        auto string_type = std::make_shared<DataTypeString>();
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto string_col = ColumnString::create();
+        string_col->insert_data("hello", 5);
+        string_col->insert_data("world", 5);
+
+        ColumnsWithTypeAndName arguments {{string_col->get_ptr(), string_type, 
"string_col"},
+                                          {nullptr, variant_type, 
"variant_type"}};
+
+        auto function = SimpleFunctionFactory::instance().get_function("CAST", 
arguments,
+                                                                       
make_nullable(variant_type));
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, variant_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
2).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* variant_col =
+                assert_cast<const 
ColumnObject*>(remove_nullable(result_col).get());
+        ASSERT_EQ(variant_col->size(), 2);
+    }
+
+    // Test casting from array to variant
+    {
+        auto array_type = 
std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt32>());
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto array_col =
+                ColumnArray::create(ColumnInt32::create(), 
ColumnArray::ColumnOffsets::create());
+        auto& data = assert_cast<ColumnInt32&>(array_col->get_data());
+        auto& offsets = array_col->get_offsets();
+
+        data.insert(1);
+        data.insert(2);
+        data.insert(3);
+        offsets.push_back(3);
+
+        ColumnsWithTypeAndName arguments {{array_col->get_ptr(), array_type, 
"array_col"},
+                                          {nullptr, variant_type, 
"variant_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, variant_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, variant_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* variant_col =
+                assert_cast<const 
ColumnObject*>(remove_nullable(result_col).get());
+        ASSERT_EQ(variant_col->size(), 1);
+    }
+}
+
+TEST(FunctionVariantCast, CastFromVariant) {
+    // Test casting from variant to basic types
+    {
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto int32_type = std::make_shared<DataTypeInt32>();
+        auto variant_col = ColumnObject::create(true);
+
+        // Create a variant column with integer values
+        variant_col->create_root(int32_type, ColumnInt32::create());
+        MutableColumnPtr data = variant_col->get_root();
+        data->insert(42);
+        data->insert(100);
+        data->insert(-1);
+
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, int32_type, "int32_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, int32_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, int32_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
3).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        // always nullable
+        const auto* int32_result =
+                assert_cast<const 
ColumnInt32*>(remove_nullable(result_col).get());
+        ASSERT_EQ(int32_result->size(), 3);
+        ASSERT_EQ(int32_result->get_element(0), 42);
+        ASSERT_EQ(int32_result->get_element(1), 100);
+        ASSERT_EQ(int32_result->get_element(2), -1);
+    }
+
+    // Test casting from variant to string
+    {
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto string_type = std::make_shared<DataTypeString>();
+        auto variant_col = ColumnObject::create(true);
+
+        // Create a variant column with string values
+        variant_col->create_root(string_type, ColumnString::create());
+        MutableColumnPtr data = variant_col->get_root();
+        data->insert_data("hello", 5);
+        data->insert_data("world", 5);
+
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, string_type, 
"string_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, string_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, string_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
2).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* string_result =
+                assert_cast<const 
ColumnString*>(remove_nullable(result_col).get());
+        ASSERT_EQ(string_result->size(), 2);
+        ASSERT_EQ(string_result->get_data_at(0).to_string(), "hello");
+        ASSERT_EQ(string_result->get_data_at(1).to_string(), "world");
+    }
+
+    // Test casting from variant to array
+    {
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto array_type = 
std::make_shared<DataTypeArray>(std::make_shared<DataTypeInt32>());
+        auto variant_col = ColumnObject::create(true);
+
+        // Create a variant column with array values
+        variant_col->create_root(
+                array_type,
+                ColumnArray::create(ColumnInt32::create(), 
ColumnArray::ColumnOffsets::create()));
+        MutableColumnPtr data = variant_col->get_root();
+
+        Field a = Array {1, 2, 3};
+
+        data->insert(a);
+
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, array_type, "array_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, array_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, array_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* array_result =
+                assert_cast<const 
ColumnArray*>(remove_nullable(result_col).get());
+        ASSERT_EQ(array_result->size(), 1);
+        const auto& result_data = assert_cast<const 
ColumnInt32&>(array_result->get_data());
+        ASSERT_EQ(result_data.size(), 3);
+        ASSERT_EQ(result_data.get_element(0), 1);
+        ASSERT_EQ(result_data.get_element(1), 2);
+        ASSERT_EQ(result_data.get_element(2), 3);
+    }
+}
+
+TEST(FunctionVariantCast, CastVariantWithNull) {
+    auto variant_type = std::make_shared<DataTypeObject>();
+    auto int32_type = std::make_shared<DataTypeInt32>();
+    auto nullable_int32_type = std::make_shared<DataTypeNullable>(int32_type);
+
+    // Create a variant column with nullable integer values
+    auto variant_col = ColumnObject::create(true);
+    variant_col->create_root(nullable_int32_type,
+                             ColumnNullable::create(ColumnInt32::create(), 
ColumnUInt8::create()));
+    MutableColumnPtr data = variant_col->get_root();
+
+    data->insert(42);
+    data->insert(Null());
+    data->insert(100);
+
+    ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), variant_type, 
"variant_col"},
+                                      {nullptr, nullable_int32_type, 
"nullable_int32_type"}};
+
+    variant_col->finalize();
+    auto function =
+            SimpleFunctionFactory::instance().get_function("CAST", arguments, 
nullable_int32_type);
+    ASSERT_NE(function, nullptr);
+
+    Block block {arguments};
+    size_t result_column = block.columns();
+    block.insert({nullptr, nullable_int32_type, "result"});
+
+    RuntimeState state;
+    auto ctx = FunctionContext::create_context(&state, {}, {});
+    ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
3).ok());
+
+    auto result_col = block.get_by_position(result_column).column;
+    ASSERT_NE(result_col.get(), nullptr);
+    const auto* nullable_result = assert_cast<const 
ColumnNullable*>(result_col.get());
+    ASSERT_EQ(nullable_result->size(), 3);
+
+    const auto& result_data = assert_cast<const 
ColumnInt32&>(nullable_result->get_nested_column());
+    const auto& result_null_map = nullable_result->get_null_map_data();
+
+    ASSERT_EQ(result_data.get_element(0), 42);
+    ASSERT_EQ(result_null_map[0], 0);
+    ASSERT_EQ(result_null_map[1], 1);
+    ASSERT_EQ(result_data.get_element(2), 100);
+}
+
+TEST(FunctionVariantCast, CastFromVariantWithEmptyRoot) {
+    // Test case 1: variant.empty() branch
+    {
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto int32_type = std::make_shared<DataTypeInt32>();
+        MutableColumnPtr root = ColumnInt32::create();
+        root->insert(42);
+        vectorized::ColumnObject::Subcolumns dynamic_subcolumns;
+        dynamic_subcolumns.add(
+                vectorized::PathInData(ColumnObject::COLUMN_NAME_DUMMY),
+                vectorized::ColumnObject::Subcolumn {root->get_ptr(), 
int32_type, true, true});
+        auto variant_col = ColumnObject::create(0, 
std::move(dynamic_subcolumns));
+
+        variant_col->finalize();
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, int32_type, "int32_type"}};
+
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, int32_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, int32_type, "result"});
+
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        // always nullable
+        const auto* int32_result =
+                assert_cast<const 
ColumnInt32*>(remove_nullable(result_col).get());
+        ASSERT_EQ(int32_result->size(), 1);
+        // because of variant.empty() we insert_default with data_type_to
+        ASSERT_EQ(int32_result->get_element(0), 0);
+    }
+
+    // Test case 2: !data_type_to->is_nullable() && 
!WhichDataType(data_type_to).is_string() branch
+    {
+        // object has sparse column
+        auto int32_type = std::make_shared<DataTypeInt32>();
+        auto variant_col = construct_basic_varint_column();
+        auto variant_type = std::make_shared<DataTypeObject>();
+
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, int32_type, "int32_type"}};
+
+        variant_col->finalize();
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, int32_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, int32_type, "result"});
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* nullable_result = assert_cast<const 
ColumnNullable*>(result_col.get());
+        ASSERT_EQ(nullable_result->size(), 1);
+        ASSERT_TRUE(nullable_result->is_null_at(0));
+    }
+
+    // Test case 3: WhichDataType(data_type_to).is_string() branch
+    {
+        // variant has sparse column
+        auto int32_type = std::make_shared<DataTypeInt32>();
+        auto variant_col = construct_basic_varint_column();
+
+        auto string_type = std::make_shared<DataTypeString>();
+        auto variant_type = std::make_shared<DataTypeObject>();
+
+        ColumnsWithTypeAndName arguments {{variant_col->get_ptr(), 
variant_type, "variant_col"},
+                                          {nullptr, string_type, 
"string_type"}};
+
+        variant_col->finalize();
+        auto function =
+                SimpleFunctionFactory::instance().get_function("CAST", 
arguments, string_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, string_type, "result"});
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* string_result = assert_cast<const 
ColumnString*>(result_col.get());
+        // just call ConvertImplGenericToString which will insert all source 
column data to ColumnString
+        ASSERT_EQ(string_result->size(), variant_col->size());
+        ASSERT_EQ(string_result->get_data_at(0).to_string(),
+                  
"{\"v\":{\"a\":20,\"b\":\"20\",\"c\":20,\"e\":\"50\",\"f\":20}}");
+    }
+
+    // Test case 4: else branch (nullable type)
+    {
+        auto variant_col = construct_basic_varint_column();
+        variant_col->finalize();
+        auto nullable_variant_col = make_nullable(variant_col->get_ptr());
+
+        auto nullable_string_type = 
make_nullable(std::make_shared<DataTypeString>());
+        auto variant_type = std::make_shared<DataTypeObject>();
+        auto nullable_variant_type = make_nullable(variant_type);
+
+        ColumnsWithTypeAndName arguments {
+                {nullable_variant_col->get_ptr(), nullable_variant_type, 
"variant_col"},
+                {nullptr, nullable_string_type, "nullable_string_type"}};
+
+        auto function = SimpleFunctionFactory::instance().get_function("CAST", 
arguments,
+                                                                       
nullable_string_type);
+        ASSERT_NE(function, nullptr);
+
+        Block block {arguments};
+        size_t result_column = block.columns();
+        block.insert({nullptr, nullable_string_type, "result"});
+        RuntimeState state;
+        auto ctx = FunctionContext::create_context(&state, {}, {});
+        ASSERT_TRUE(function->execute(ctx.get(), block, {0}, result_column, 
1).ok());
+
+        auto result_col = block.get_by_position(result_column).column;
+        ASSERT_NE(result_col.get(), nullptr);
+        const auto* nullable_result = assert_cast<const 
ColumnNullable*>(result_col.get());
+        ASSERT_EQ(nullable_result->size(), 1);
+        ASSERT_TRUE(nullable_result->is_null_at(1));
+    }
+}
+
+} // namespace doris::vectorized
diff --git a/be/test/vec/jsonb/convert_field_to_type_test.cpp 
b/be/test/vec/jsonb/convert_field_to_type_test.cpp
new file mode 100644
index 00000000000..065d86c039c
--- /dev/null
+++ b/be/test/vec/jsonb/convert_field_to_type_test.cpp
@@ -0,0 +1,521 @@
+// 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 "vec/data_types/convert_field_to_type.cpp"
+
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <string>
+
+#include "runtime/jsonb_value.h"
+#include "util/jsonb_document.h"
+#include "util/jsonb_writer.h"
+#include "vec/core/field.h"
+#include "vec/core/types.h"
+#include "vec/data_types/data_type.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/data_types/data_type_jsonb.h"
+#include "vec/data_types/data_type_nullable.h"
+
+namespace doris::vectorized {
+
+class ConvertFieldToTypeTest : public ::testing::Test {
+protected:
+    void SetUp() override {}
+};
+
+// Test FieldVisitorToJsonb with different field types using the same pattern 
as convert_field_to_typeImpl
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_Null) {
+    JsonbWriter writer;
+
+    // Test null field using Field::dispatch pattern
+    Field null_field;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    null_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's a null value
+    ASSERT_TRUE(doc->getValue()->isNull());
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_Int64) {
+    JsonbWriter writer;
+
+    // Test Int64 field using Field::dispatch pattern
+    Int64 test_value = 12345;
+    Field int_field = test_value;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    int_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an integer value
+    ASSERT_TRUE(doc->getValue()->isInt64());
+    ASSERT_EQ(((const JsonbIntVal*)doc->getValue())->val(), test_value);
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_UInt64) {
+    JsonbWriter writer;
+
+    // Test UInt64 field using Field::dispatch pattern
+    UInt64 test_value = 12345;
+    Field uint_field = test_value;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    uint_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an integer value
+    ASSERT_TRUE(doc->getValue()->isInt64());
+    ASSERT_EQ(((const JsonbIntVal*)doc->getValue())->val(), 
static_cast<Int64>(test_value));
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_Float64) {
+    JsonbWriter writer;
+
+    // Test Float64 field using Field::dispatch pattern
+    Float64 test_value = 123.456;
+    Field double_field = test_value;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    double_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's a double value
+    ASSERT_TRUE(doc->getValue()->isDouble());
+    ASSERT_DOUBLE_EQ(((const JsonbDoubleVal*)doc->getValue())->val(), 
test_value);
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_String) {
+    JsonbWriter writer;
+
+    // Test String field using Field::dispatch pattern
+    Field string_field = "hello world";
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    string_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's a string value
+    ASSERT_TRUE(doc->getValue()->isString());
+    const auto* string_val = static_cast<const JsonbBlobVal*>(doc->getValue());
+    std::string real_string(string_val->getBlob(), string_val->getBlobLen());
+    ASSERT_EQ(real_string, string_field.get<String>());
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_JsonbField) {
+    JsonbWriter writer;
+    JsonBinaryValue jsonb_value;
+    std::string test_data = R"({"a": ["1", "2"]})";
+    THROW_IF_ERROR(jsonb_value.from_json_string(test_data.data(), 
test_data.size()));
+    Field jsonb_field_obj = JsonbField(jsonb_value.value(), 
jsonb_value.size());
+
+    // Test JsonbField using Field::dispatch pattern
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    jsonb_field_obj);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an object value
+    ASSERT_TRUE(doc->getValue()->isObject());
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_Array) {
+    JsonbWriter writer;
+
+    // Create an array with mixed types
+    Array array_field;
+    array_field.push_back(123);
+    array_field.push_back("hello");
+    array_field.push_back(456.789);
+
+    Field array_obj = array_field;
+
+    // Test Array using Field::dispatch pattern
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    array_obj);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an array value
+    ASSERT_TRUE(doc->getValue()->isArray());
+    const ArrayVal& array = static_cast<const ArrayVal&>(*doc->getValue());
+    ASSERT_EQ(array.numElem(), 3);
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_NestedArray) {
+    JsonbWriter writer;
+
+    // Create a nested array
+    Array inner_array;
+    inner_array.push_back(1);
+    inner_array.push_back(2);
+
+    Array outer_array;
+    outer_array.push_back(inner_array);
+    outer_array.push_back("nested");
+
+    Field nested_array_obj = outer_array;
+
+    // Test nested Array using Field::dispatch pattern
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    nested_array_obj);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an array value
+    ASSERT_TRUE(doc->getValue()->isArray());
+    const ArrayVal& array = static_cast<const ArrayVal&>(*doc->getValue());
+    ASSERT_EQ(array.numElem(), 2);
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_LargeInt) {
+    JsonbWriter writer;
+
+    // Test Int128 field using Field::dispatch pattern
+    Int128 test_value = 1234567890123456789;
+    Field largeint_field = test_value;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    largeint_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an int128 value
+    ASSERT_TRUE(doc->getValue()->isInt128());
+    ASSERT_EQ(((const JsonbIntVal*)doc->getValue())->val(), test_value);
+}
+
+TEST_F(ConvertFieldToTypeTest, FieldVisitorToJsonb_UInt128) {
+    JsonbWriter writer;
+
+    // Test UInt128 field using Field::dispatch pattern
+    UInt128 test_value = 1234567890123456789;
+    Field uint128_field = test_value;
+    Field::dispatch([&writer](const auto& value) { 
FieldVisitorToJsonb()(value, &writer); },
+                    uint128_field);
+
+    auto* output = writer.getOutput();
+    ASSERT_NE(output, nullptr);
+    ASSERT_GT(output->getSize(), 0);
+
+    // Verify the output is valid JSONB
+    JsonbDocument* doc = nullptr;
+    auto status =
+            JsonbDocument::checkAndCreateDocument(output->getBuffer(), 
output->getSize(), &doc);
+    ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+    ASSERT_NE(doc, nullptr);
+
+    // Verify it's an int128 value
+    ASSERT_TRUE(doc->getValue()->isInt128());
+    ASSERT_EQ(((const JsonbIntVal*)doc->getValue())->val(), 
static_cast<Int128>(test_value));
+}
+
+// Test convert_field_to_type function with JSONB type (similar to 
convert_field_to_typeImpl)
+TEST_F(ConvertFieldToTypeTest, ConvertFieldToType_ToJsonb) {
+    DataTypeJsonb jsonb_type;
+
+    // Test converting Int64 to JSONB
+    {
+        Int64 test_value = 12345;
+        Field int_field = test_value;
+        Field result;
+
+        convert_field_to_type(int_field, jsonb_type, &result);
+
+        ASSERT_EQ(result.get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result.is_null());
+
+        const JsonbField& jsonb_result = result.get<JsonbField>();
+        ASSERT_NE(jsonb_result.get_value(), nullptr);
+        ASSERT_GT(jsonb_result.get_size(), 0);
+
+        // Verify the JSONB content
+        JsonbDocument* doc = nullptr;
+        auto status = 
JsonbDocument::checkAndCreateDocument(jsonb_result.get_value(),
+                                                            
jsonb_result.get_size(), &doc);
+        ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+        ASSERT_NE(doc, nullptr);
+        ASSERT_TRUE(doc->getValue()->isInt64());
+        ASSERT_EQ(((const JsonbIntVal*)doc->getValue())->val(), test_value);
+    }
+
+    // Test converting String to JSONB
+    {
+        Field string_field = "hello world";
+        Field result;
+
+        convert_field_to_type(string_field, jsonb_type, &result);
+
+        ASSERT_EQ(result.get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result.is_null());
+
+        const JsonbField& jsonb_result = result.get<JsonbField>();
+        ASSERT_NE(jsonb_result.get_value(), nullptr);
+        ASSERT_GT(jsonb_result.get_size(), 0);
+
+        // Verify the JSONB content
+        JsonbDocument* doc = nullptr;
+        auto status = 
JsonbDocument::checkAndCreateDocument(jsonb_result.get_value(),
+                                                            
jsonb_result.get_size(), &doc);
+        ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+        ASSERT_NE(doc, nullptr);
+        ASSERT_TRUE(doc->getValue()->isString());
+        const auto* string_val = static_cast<const 
JsonbBlobVal*>(doc->getValue());
+        std::string real_string(string_val->getBlob(), 
string_val->getBlobLen());
+        ASSERT_EQ(real_string, string_field.get<String>());
+    }
+
+    // Test converting Array to JSONB
+    {
+        Array array_field;
+        array_field.push_back(1);
+        array_field.push_back("test");
+        array_field.push_back(3.14);
+
+        Field array_obj = array_field;
+        Field result;
+
+        convert_field_to_type(array_obj, jsonb_type, &result);
+
+        ASSERT_EQ(result.get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result.is_null());
+
+        const JsonbField& jsonb_result = result.get<JsonbField>();
+        ASSERT_NE(jsonb_result.get_value(), nullptr);
+        ASSERT_GT(jsonb_result.get_size(), 0);
+
+        // Verify the JSONB content
+        JsonbDocument* doc = nullptr;
+        auto status = 
JsonbDocument::checkAndCreateDocument(jsonb_result.get_value(),
+                                                            
jsonb_result.get_size(), &doc);
+        ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+        ASSERT_NE(doc, nullptr);
+        ASSERT_TRUE(doc->getValue()->isArray());
+        const ArrayVal& array = static_cast<const ArrayVal&>(*doc->getValue());
+        ASSERT_EQ(array.numElem(), 3);
+    }
+
+    // Test converting JSONB to JSONB (should be no-op)
+    {
+        JsonbWriter test_writer;
+        test_writer.writeStartObject();
+        test_writer.writeKey("key");
+        test_writer.writeString("value");
+        test_writer.writeEndObject();
+
+        auto* test_output = test_writer.getOutput();
+        JsonbField original_jsonb(test_output->getBuffer(), 
test_output->getSize());
+        Field jsonb_field = original_jsonb;
+        Field result;
+
+        convert_field_to_type(jsonb_field, jsonb_type, &result);
+
+        ASSERT_EQ(result.get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result.is_null());
+
+        const JsonbField& jsonb_result = result.get<JsonbField>();
+        ASSERT_NE(jsonb_result.get_value(), nullptr);
+        ASSERT_EQ(jsonb_result.get_size(), original_jsonb.get_size());
+        ASSERT_EQ(memcmp(jsonb_result.get_value(), original_jsonb.get_value(),
+                         original_jsonb.get_size()),
+                  0);
+    }
+}
+
+// Test convert_field_to_type with nullable JSONB type
+TEST_F(ConvertFieldToTypeTest, ConvertFieldToType_ToNullableJsonb) {
+    auto nullable_jsonb_type =
+            
std::make_shared<DataTypeNullable>(std::make_shared<DataTypeJsonb>());
+
+    // Test converting null field
+    {
+        Field null_field;
+        Field result;
+
+        convert_field_to_type(null_field, *nullable_jsonb_type, &result);
+
+        ASSERT_TRUE(result.is_null());
+    }
+
+    // Test converting non-null field
+    {
+        Field string_field = "test string";
+        Field result;
+
+        convert_field_to_type(string_field, *nullable_jsonb_type, &result);
+
+        ASSERT_EQ(result.get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result.is_null());
+
+        const JsonbField& jsonb_result = result.get<JsonbField>();
+        ASSERT_NE(jsonb_result.get_value(), nullptr);
+        ASSERT_GT(jsonb_result.get_size(), 0);
+
+        // Verify the JSONB content
+        JsonbDocument* doc = nullptr;
+        auto status = 
JsonbDocument::checkAndCreateDocument(jsonb_result.get_value(),
+                                                            
jsonb_result.get_size(), &doc);
+        ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument: " << 
status.to_string();
+        ASSERT_NE(doc, nullptr);
+        ASSERT_TRUE(doc->getValue()->isString());
+        const auto* string_val = static_cast<const 
JsonbBlobVal*>(doc->getValue());
+        std::string real_string(string_val->getBlob(), 
string_val->getBlobLen());
+        ASSERT_EQ(real_string, string_field.get<String>());
+    }
+}
+
+// Test convert_field_to_type with array of JSONB
+TEST_F(ConvertFieldToTypeTest, ConvertFieldToType_ArrayToJsonb) {
+    auto array_jsonb_type = 
std::make_shared<DataTypeArray>(std::make_shared<DataTypeJsonb>());
+
+    // Create an array with mixed types that will be converted to JSONB
+    Array array_field;
+    array_field.push_back(123);
+    array_field.push_back("hello");
+    array_field.push_back(456.789);
+
+    Field array_obj = array_field;
+    Field result;
+
+    convert_field_to_type(array_obj, *array_jsonb_type, &result);
+
+    ASSERT_EQ(result.get_type(), Field::Types::Array);
+    ASSERT_FALSE(result.is_null());
+
+    const Array& result_array = result.get<Array>();
+    ASSERT_EQ(result_array.size(), 3);
+
+    // Verify each element is converted to JSONB
+    for (size_t i = 0; i < result_array.size(); ++i) {
+        ASSERT_EQ(result_array[i].get_type(), Field::Types::JSONB);
+        ASSERT_FALSE(result_array[i].is_null());
+
+        const auto& jsonb_element = result_array[i].get<JsonbField>();
+        ASSERT_NE(jsonb_element.get_value(), nullptr);
+        ASSERT_GT(jsonb_element.get_size(), 0);
+
+        // Verify the JSONB content
+        JsonbDocument* doc = nullptr;
+        auto status = 
JsonbDocument::checkAndCreateDocument(jsonb_element.get_value(),
+                                                            
jsonb_element.get_size(), &doc);
+        ASSERT_TRUE(status.ok()) << "Failed to create JsonbDocument for 
element " << i << ": "
+                                 << status.to_string();
+        ASSERT_NE(doc, nullptr);
+    }
+}
+
+// Test error cases
+TEST_F(ConvertFieldToTypeTest, ConvertFieldToType_ErrorCases) {
+    DataTypeJsonb jsonb_type;
+
+    // Test with unsupported types (should throw exception)
+    {
+        Field tuple_field = Tuple();
+
+        EXPECT_THROW(
+                {
+                    Field result;
+                    convert_field_to_type(tuple_field, jsonb_type, &result);
+                },
+                doris::Exception);
+    }
+}
+
+} // namespace doris::vectorized
\ No newline at end of file
diff --git a/be/test/vec/jsonb/json_parser_test.cpp 
b/be/test/vec/jsonb/json_parser_test.cpp
new file mode 100644
index 00000000000..257a7c370c7
--- /dev/null
+++ b/be/test/vec/jsonb/json_parser_test.cpp
@@ -0,0 +1,169 @@
+// 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 "vec/json/json_parser.h"
+
+#include <gtest/gtest.h>
+
+#include <vector>
+
+using doris::vectorized::JSONDataParser;
+using doris::vectorized::SimdJSONParser;
+using doris::vectorized::ParseConfig;
+
+TEST(JsonParserTest, ParseSimpleTypes) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+
+    // int
+    auto result = parser.parse("123", 3, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+
+    // double
+    result = parser.parse("1.23", 4, config);
+    ASSERT_TRUE(result.has_value());
+
+    // bool
+    result = parser.parse("true", 4, config);
+    ASSERT_TRUE(result.has_value());
+
+    // null
+    result = parser.parse("null", 4, config);
+    ASSERT_TRUE(result.has_value());
+
+    // string
+    result = parser.parse("\"abc\"", 5, config);
+    ASSERT_TRUE(result.has_value());
+}
+
+TEST(JsonParserTest, ParseObjectAndArray) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+
+    // Object
+    auto result = parser.parse(R"({"a":1,"b":2})", 13, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 2);
+
+    // Array
+    result = parser.parse("[1,2,3]", 7, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+}
+
+TEST(JsonParserTest, ParseMultiLevelNestedArray) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+
+    auto result = parser.parse("[[1,2],[3,4]]", 13, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::Array);
+
+    result = parser.parse("[[[1],[2]],[[3],[4]]]", 21, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::Array);
+
+    result = parser.parse("[[1,2],[3],[4,5,6]]", 19, config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+
+    // Test complex nested structure
+    config.enable_flatten_nested = false;
+    std::string json1 = R"({"a":[[1,2],[3],[4,5,6]]})";
+    // multi level nested array in object
+    result = parser.parse(json1.c_str(), json1.size(), config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::Array);
+
+    std::string json = R"({"nested": [{"a": [1,2,3]}]})";
+    // result should be jsonbField
+    result = parser.parse(json.c_str(), json.size(), config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::JSONB);
+
+    // multi level nested array in nested array object
+    std::string json2 = R"({"a":[{"b":[[1,2,3]]}]})";
+    result = parser.parse(json2.c_str(), json2.size(), config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::JSONB);
+
+    // test flatten nested
+    config.enable_flatten_nested = true;
+    EXPECT_ANY_THROW(parser.parse(json.c_str(), json.size(), config));
+    // test flatten nested with multi level nested array
+    // no throw because it is not nested object array
+    result = parser.parse(json1.c_str(), json1.size(), config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_EQ(result->values.size(), 1);
+    EXPECT_EQ(result->paths.size(), 1);
+    EXPECT_EQ(result->values[0].get_type(), 
doris::vectorized::Field::Types::Array);
+
+    EXPECT_ANY_THROW(parser.parse(json2.c_str(), json2.size(), config));
+}
+
+TEST(JsonParserTest, ParseNestedAndFlatten) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+    config.enable_flatten_nested = true;
+
+    std::string json = R"({"a":[{"b":1},{"b":2}]})";
+    auto result = parser.parse(json.c_str(), json.size(), config);
+    ASSERT_TRUE(result.has_value());
+    EXPECT_GT(result->values.size(), 0);
+
+    config.enable_flatten_nested = false;
+    std::string json2 = R"({"a":[{"b":1},{"b":2}]})";
+    result = parser.parse(json2.c_str(), json2.size(), config);
+    ASSERT_TRUE(result.has_value());
+}
+
+TEST(JsonParserTest, ParseInvalidJson) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+
+    auto result = parser.parse("{a:1}", 5, config);
+    ASSERT_FALSE(result.has_value());
+
+    result = parser.parse("", 0, config);
+    ASSERT_FALSE(result.has_value());
+}
+
+TEST(JsonParserTest, ParseCornerCases) {
+    JSONDataParser<SimdJSONParser> parser;
+    ParseConfig config;
+
+    auto result = parser.parse("{}", 2, config);
+    ASSERT_TRUE(result.has_value());
+
+    result = parser.parse("[]", 2, config);
+    ASSERT_TRUE(result.has_value());
+
+    result = parser.parse(R"({"a":"\n\t"})", 12, config);
+    ASSERT_TRUE(result.has_value());
+}
diff --git a/regression-test/data/variant_p0/desc.out 
b/regression-test/data/variant_p0/desc.out
index 1eff52e4484..71f804cc25c 100644
Binary files a/regression-test/data/variant_p0/desc.out and 
b/regression-test/data/variant_p0/desc.out differ
diff --git a/regression-test/data/variant_p0/load.out 
b/regression-test/data/variant_p0/load.out
index 300c97a8dfb..fefa6a3dc7a 100644
Binary files a/regression-test/data/variant_p0/load.out and 
b/regression-test/data/variant_p0/load.out differ
diff --git a/regression-test/data/variant_p0/nested2.out 
b/regression-test/data/variant_p0/nested2.out
new file mode 100644
index 00000000000..3703c7e5aa8
Binary files /dev/null and b/regression-test/data/variant_p0/nested2.out differ
diff --git a/regression-test/suites/variant_p0/nested2.groovy 
b/regression-test/suites/variant_p0/nested2.groovy
new file mode 100644
index 00000000000..73180128bfb
--- /dev/null
+++ b/regression-test/suites/variant_p0/nested2.groovy
@@ -0,0 +1,151 @@
+// 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.
+
+// this test is used to test the type conflict of nested array
+suite("variant_nested_type_conflict", "p0"){
+
+    try {
+
+        def table_name = "var_nested_type_conflict"
+        sql "DROP TABLE IF EXISTS ${table_name}"
+        sql """set describe_extend_variant_column = true"""
+
+        sql """
+                CREATE TABLE IF NOT EXISTS ${table_name} (
+                    k bigint,
+                    v variant
+                )
+                DUPLICATE KEY(`k`)
+                DISTRIBUTED BY HASH(k) BUCKETS 1 -- 1 bucket make really 
compaction in conflict case
+                properties("replication_num" = "1", "disable_auto_compaction" 
= "false", "variant_enable_flatten_nested" = "true");
+            """
+        def sql_select_batch = {
+            qt_sql_0 """select * from ${table_name} order by k"""
+
+            qt_sql_1 """select v['nested']['a'] from ${table_name} order by 
k"""
+            qt_sql_2 """select v['nested']['b'] from ${table_name} order by 
k"""
+            qt_sql_3 """select v['nested']['c'] from ${table_name} order by 
k"""
+
+            qt_sql_4 """select v['nested'] from ${table_name} order by k"""
+        }
+
+        def sql_test_cast_to_array = {
+            // test cast to array<int> 
+            qt_sql_8 """select cast(v['nested']['a'] as array<int>), 
size(cast(v['nested']['a'] as array<int>)) from ${table_name} order by k"""
+            qt_sql_9 """select cast(v['nested']['b'] as array<int>), 
size(cast(v['nested']['b'] as array<int>)) from ${table_name} order by k"""
+            qt_sql_10 """select cast(v['nested']['c'] as array<int>), 
size(cast(v['nested']['c'] as array<int>)) from ${table_name} order by k"""
+
+            // test cast to array<string> 
+            qt_sql_11 """select cast(v['nested']['a'] as array<string>), 
size(cast(v['nested']['a'] as array<string>)) from ${table_name} order by k"""
+            qt_sql_12 """select cast(v['nested']['b'] as array<string>), 
size(cast(v['nested']['b'] as array<string>)) from ${table_name} order by k"""
+            qt_sql_13 """select cast(v['nested']['c'] as array<string>), 
size(cast(v['nested']['c'] as array<string>)) from ${table_name} order by k"""
+
+            // test cast to array<double> 
+            qt_sql_14 """select cast(v['nested']['a'] as array<double>), 
size(cast(v['nested']['a'] as array<double>)) from ${table_name} order by k"""
+            qt_sql_15 """select cast(v['nested']['b'] as array<double>), 
size(cast(v['nested']['b'] as array<double>)) from ${table_name} order by k"""
+            qt_sql_16 """select cast(v['nested']['c'] as array<double>), 
size(cast(v['nested']['c'] as array<double>)) from ${table_name} order by k"""
+
+        }
+        // insert Nested array in Nested array which is not supported
+        test {
+            sql """
+                insert into ${table_name} values (1, '{"nested": [{"a": 
[1,2,3]}]}');
+                """
+            exception "Nesting of array in Nested array within variant 
subcolumns is currently not supported."
+        }
+        /// insert a array of object for a, b, c 
+        // insert type conflict in multiple rows
+        sql """
+            insert into ${table_name} values (1, '{"nested": [{"a": 1, "c": 
1.1}, {"b": "1"}]}'); 
+            """
+
+        // for cloud we should select first and then desc for syncing rowset 
to get latest schema
+        sql """
+            select * from ${table_name} order by k limit 1;
+            """
+        qt_sql_desc_1 """
+            select variant_type(v) from ${table_name} order by k 
+            """
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+        /// insert a, b type changed to double 
+        sql """
+            insert into ${table_name} values (2, '{"nested": [{"a": 2.5, "b": 
123.1}]}');
+            """
+        // for cloud we should select first and then desc for syncing rowset 
to get latest schema
+        sql """
+            select * from ${table_name} order by k limit 1;
+            """
+        qt_sql_desc_2 """
+            select variant_type(v) from ${table_name} order by k 
+            """
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+
+        // trigger and wait compaction
+        trigger_and_wait_compaction("${table_name}", "full")
+
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+
+        sql """ truncate table ${table_name} """
+
+
+        // insert type conflict in one row
+        sql """
+            insert into ${table_name} values (1, '{"nested": [{"a": 1, "b": 
1.1}, {"a": "1", "b": "1", "c": "1"}]}');
+            """
+        // for cloud we should select first and then desc for syncing rowset 
to get latest schema
+        sql """
+            select * from ${table_name} order by k limit 1;
+            """
+        qt_sql_desc_4 """
+               select variant_type(v) from ${table_name} order by k 
+            """
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+
+        // insert c type changed to double
+        sql """
+            insert into ${table_name} values (2, '{"nested": [{"a": 1, "c": 
1.1}]}');
+            """
+        // for cloud we should select first and then desc for syncing rowset 
to get latest schema
+        sql """
+            select * from ${table_name} order by k limit 1;
+            """
+        qt_sql_desc_5 """
+            select variant_type(v) from ${table_name} order by k 
+            """
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+
+        // trigger and wait compaction
+        trigger_and_wait_compaction("${table_name}", "full")
+
+        // now select for a, b, c
+        sql_select_batch()
+        sql_test_cast_to_array()
+
+    } finally {
+    }
+
+}


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

Reply via email to