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

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


The following commit(s) were added to refs/heads/branch-4.2 by this push:
     new 542108dfe75 branch-4.2: [improvement](variant) Remove BE configs that 
change Variant JSON parse errors (#69260)
542108dfe75 is described below

commit 542108dfe758835982c3437e54fe88aeca99a66c
Author: lihangyu <[email protected]>
AuthorDate: Tue Oct 20 16:52:01 2026 +0800

    branch-4.2: [improvement](variant) Remove BE configs that change Variant 
JSON parse errors (#69260)
    
    cherry-pick #68447
    
    Adapted to branch-4.2, which still has the V1 Variant writer and the
    `enable_variant_v2` FE
    switch:
    
    - V1 call sites that read the two removed BE configs (`variant_util`,
    `function_variant_parse`, `data_type_variant_serde`) now always reject
    duplicate paths and
    invalid JSON, matching the new V2 default. `ParseConfig` gained
    `throw_on_invalid_json`
    (default `true`) so the Variant serde keeps reading back values the
    parser cannot parse,
      like the V2 serde does.
    - `duplicate_json_path.groovy`, `column_name.groovy` and
    `variant_compute_v2.groovy` keep the
    branch-4.2 `enable_variant_v2` gating and the V1/V2 expectations; only
    the removed BE config
      wrapper is dropped.
    - Tests that toggled the removed configs (`variant_util_test`,
    `index_storage_test_util`, the
    `JsonToVariantOptions::check_duplicate_json_path` initializers) are
    updated accordingly.
    
    Tested locally with
    `./run-be-ut.sh --run
    
--filter='VariantUtilTest.*:FunctionVariantParseTest.*:VariantFieldTest.*:ColumnVariantV2Test.*:DataTypeVariantV2Serde*.*:VariantJson*Test.*:VariantColumnWriterReaderTest.*'`
    (branch-4.2 code + this pick, RELEASE build): 203 tests ran, 192 passed,
    2 skipped, 9 failed.
    
    All 9 failures also happen on branch-4.2 without this change:
    
    - 8 `ColumnVariantV2Test` death tests
    (`DefaultRowsUseCanonicalEmptyObjectAndReuseMetadata`,
    `InPlaceFilterPrevalidatesInputs`,
    `PopBackAndResizeCoverBoundsShrinkAndGrowth`,
      `RejectsInvalidBulkOffsetsAndMetadataIds`, `EncodedRowCountInvariant`,
      `MetadataIdInvariant`, `TypedConstructionAndNullableInvariant`,
    `TypedEncodedInsertMatrixKeepsConstSource`): they use `EXPECT_DEATH`,
    but
    `doris_check_fail` throws an exception instead of aborting, so the
    statement never dies.
    - `VariantColumnWriterReaderTest.test_nested_iter`:
    `_process_nested_columns` returns OK for a
      different array offset.
    
    The rewritten regression suites were not run locally (they need a
    cluster).
---
 be/src/common/config.cpp                           |   2 -
 be/src/common/config.h                             |   4 -
 .../data_type_serde/data_type_variant_serde.cpp    |   1 -
 .../data_type_serde/data_type_variant_v2_serde.cpp |  12 +-
 be/src/exec/common/variant_util.cpp                |   3 +-
 be/src/exprs/function/function_variant_parse.cpp   |   5 +-
 .../exprs/function/parse/variant_string_parse.cpp  |  48 +-----
 be/src/exprs/function/parse/variant_string_parse.h |   6 +-
 .../segment/variant/v2/variant_shredder.cpp        |  15 +-
 .../storage/segment/variant/v2/variant_shredder.h  |   1 -
 .../segment/variant/variant_writer_helpers.cpp     |   2 -
 be/src/util/json/json_parser.cpp                   |   4 +-
 be/src/util/json/json_parser.h                     |   6 +-
 be/test/core/column/column_variant_v2_test.cpp     |  14 +-
 .../data_type_serde/data_type_serde_arrow_test.cpp |  10 +-
 ...type_variant_v2_serde_binary_roundtrip_test.cpp |   4 +-
 .../data_type_variant_v2_serde_input_test.cpp      |  50 ++----
 .../data_type_variant_v2_serde_jsonb_test.cpp      |   5 +-
 .../data_type_variant_v2_serde_output_test.cpp     |   5 +-
 .../function_variant_element_v2_encoded_test.cpp   |   5 +-
 .../exprs/function/function_variant_parse_test.cpp |  69 ++++----
 be/test/exprs/variant_v2_execution_test.cpp        |   5 +-
 .../format/transformer/vparquet_writer_test.cpp    |  10 +-
 .../variant/variant_column_writer_reader_test.cpp  |  89 ++--------
 be/test/storage/variant/variant_util_test.cpp      |  32 ----
 be/test/testutil/index_storage_test_util.cpp       |   1 -
 be/test/testutil/index_storage_test_util.h         |   1 -
 be/test/util/variant/variant_field_test.cpp        |   4 +-
 be/test/util/variant/variant_string_parse_test.cpp |  75 ++-------
 .../write/test_paimon_write_variant_errors.out     |   2 +-
 .../data/variant_p0/v2/variant_parse_functions.out |   8 +-
 .../write/test_paimon_write_variant_errors.groovy  |   3 +-
 .../suites/variant_p0/column_name.groovy           |  21 ++-
 .../suites/variant_p0/duplicate_json_path.groovy   | 185 ++++++++++-----------
 .../variant_p0/test_variant_json_functions.groovy  |   3 +-
 .../suites/variant_p0/v2/variant_compute_v2.groovy |  30 ++--
 .../variant_p0/v2/variant_parse_functions.groovy   |  85 ++++------
 37 files changed, 293 insertions(+), 532 deletions(-)

diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp
index 705fcdd35db..295cc4e556a 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -1198,8 +1198,6 @@ DEFINE_mInt64(workload_group_scan_task_wait_timeout_ms, 
"10000");
 DEFINE_mBool(variant_use_cloud_schema_dict_cache, "true");
 DEFINE_mInt64(variant_threshold_rows_to_estimate_sparse_column, "2048");
 DEFINE_mInt32(variant_max_json_key_length, "255");
-DEFINE_mBool(variant_throw_exeception_on_invalid_json, "false");
-DEFINE_mBool(variant_enable_duplicate_json_path_check, "false");
 // Controls storage-layer parse target for plain non-doc VARIANT columns:
 // 0 = auto, 1 = force parse-time subcolumns, 2 = force doc-value KV staging.
 // NestedGroup, deprecated flatten-nested, and persistent doc mode keep their 
required paths.
diff --git a/be/src/common/config.h b/be/src/common/config.h
index 5c7ff731260..f3db5f1a5af 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -1558,10 +1558,6 @@ DECLARE_mBool(variant_use_cloud_schema_dict_cache);
 DECLARE_mInt64(variant_threshold_rows_to_estimate_sparse_column);
 // Max json key length in bytes when parsing json into variant 
subcolumns/jsonb.
 DECLARE_mInt32(variant_max_json_key_length);
-// Treat invalid json format str as string, instead of throwing exception if 
false
-DECLARE_mBool(variant_throw_exeception_on_invalid_json);
-// Enable duplicate path check when parsing json into variant subcolumns/jsonb.
-DECLARE_mBool(variant_enable_duplicate_json_path_check);
 // Controls storage-layer parse target for plain non-doc VARIANT columns:
 // 0 = auto, 1 = force parse-time subcolumns, 2 = force doc-value KV staging.
 DECLARE_mInt32(variant_storage_parse_mode);
diff --git a/be/src/core/data_type_serde/data_type_variant_serde.cpp 
b/be/src/core/data_type_serde/data_type_variant_serde.cpp
index e0ddd20b7d6..df5b3112e3f 100644
--- a/be/src/core/data_type_serde/data_type_variant_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_variant_serde.cpp
@@ -138,7 +138,6 @@ Status 
DataTypeVariantSerDe::serialize_one_cell_to_json(const IColumn& column, i
 Status DataTypeVariantSerDe::deserialize_one_cell_from_json(IColumn& column, 
Slice& slice,
                                                             const 
FormatOptions& options) const {
     ParseConfig parse_config;
-    parse_config.check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check;
     StringRef json_ref(slice.data, slice.size);
     RETURN_IF_CATCH_EXCEPTION(
             variant_util::parse_json_to_variant(column, json_ref, nullptr, 
parse_config));
diff --git a/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp 
b/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
index 20c7ba92936..121ba607d53 100644
--- a/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
+++ b/be/src/core/data_type_serde/data_type_variant_v2_serde.cpp
@@ -388,12 +388,20 @@ void require_jsonb_write(bool written, const char* 
operation) {
     }
 }
 
+// Most JSON text read here was written by a Variant serde, for example into 
an aggregate state, so
+// it must read back every value a Variant can hold, including keys longer 
than the parse limit. A
+// CAST from a JSON string to ARRAY<VARIANT> or STRUCT also passes the 
elements it splits out.
+JsonToVariantOptions serde_json_options() {
+    return {.max_json_key_length = std::numeric_limits<uint32_t>::max(),
+            .throw_on_invalid_json = false};
+}
+
 } // namespace
 
 Status DataTypeVariantV2SerDe::deserialize_one_cell_from_json(IColumn& column, 
Slice& slice,
                                                               const 
FormatOptions&) const {
     RETURN_IF_CATCH_EXCEPTION({
-        JsonStringToVariantEncoder encoder;
+        JsonStringToVariantEncoder encoder(serde_json_options());
         encoder.add_json({slice.data, slice.size});
         VariantBatchBuilder block = encoder.finish_batch();
         destination(column).insert_encoded_batch(block);
@@ -436,7 +444,7 @@ Status 
DataTypeVariantV2SerDe::deserialize_column_from_json_vector(IColumn& colu
         if (slices.empty()) {
             return Status::OK();
         }
-        JsonStringToVariantEncoder encoder;
+        JsonStringToVariantEncoder encoder(serde_json_options());
         for (const Slice& slice : slices) {
             encoder.add_json({slice.data, slice.size});
         }
diff --git a/be/src/exec/common/variant_util.cpp 
b/be/src/exec/common/variant_util.cpp
index 274691304f1..4ebb549e076 100644
--- a/be/src/exec/common/variant_util.cpp
+++ b/be/src/exec/common/variant_util.cpp
@@ -1868,7 +1868,7 @@ void parse_json_to_variant_impl(IColumn& column, const 
char* src, size_t length,
     }
     if (!result) {
         VLOG_DEBUG << "failed to parse " << std::string_view(src, length) << 
", length= " << length;
-        if (config::variant_throw_exeception_on_invalid_json) {
+        if (config.throw_on_invalid_json) {
             throw doris::Exception(ErrorCode::INVALID_ARGUMENT, "Failed to 
parse object {}",
                                    std::string_view(src, length));
         }
@@ -2266,7 +2266,6 @@ Status parse_and_materialize_variant_columns(Block& 
block, const TabletSchema& t
         // Deprecated legacy flatten-nested switch. Distinct from 
variant_enable_nested_group.
         configs[i].deprecated_enable_flatten_nested =
                 tablet_schema.deprecated_variant_flatten_nested();
-        configs[i].check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check;
         const auto& column = tablet_schema.column(variant_schema_pos[i]);
         if (!column.is_variant_type()) {
             return Status::InternalError("column is not variant type, column 
name: {}",
diff --git a/be/src/exprs/function/function_variant_parse.cpp 
b/be/src/exprs/function/function_variant_parse.cpp
index c41b2316afb..3699cbc888b 100644
--- a/be/src/exprs/function/function_variant_parse.cpp
+++ b/be/src/exprs/function/function_variant_parse.cpp
@@ -80,8 +80,9 @@ public:
             const bool enable_doc_mode = variant_type->enable_doc_mode();
             auto values = ColumnVariant::create(max_subcolumns_count, 
enable_doc_mode);
             ParseConfig parse_config;
-            parse_config.check_duplicate_json_path =
-                    config::variant_enable_duplicate_json_path_check;
+            // parse_to_variant() rejects text that is not a JSON document; 
try_parse_to_variant()
+            // turns the failure into NULL below.
+            parse_config.throw_on_invalid_json = true;
             parse_config.parse_to = enable_doc_mode ? 
ParseConfig::ParseTo::OnlyDocValueColumn
                                                     : 
ParseConfig::ParseTo::OnlySubcolumns;
             JsonParser parser;
diff --git a/be/src/exprs/function/parse/variant_string_parse.cpp 
b/be/src/exprs/function/parse/variant_string_parse.cpp
index 1c24037747b..289b607fdc5 100644
--- a/be/src/exprs/function/parse/variant_string_parse.cpp
+++ b/be/src/exprs/function/parse/variant_string_parse.cpp
@@ -27,7 +27,6 @@
 #include <cstdint>
 #include <limits>
 #include <string_view>
-#include <unordered_set>
 #include <utility>
 
 #include "common/config.h"
@@ -171,44 +170,14 @@ private:
 
     void collect_object(const SimdJSONParser::Object& object, uint32_t depth) {
         auto scope = _builder.start_object();
-        if (!_options.check_duplicate_json_path) {
-            for (const auto& [key, child] : object) {
-                require_json_key_length(key, _options.max_json_key_length);
-                scope.add_key(to_string_ref(key));
-                collect(child, depth + 1);
-            }
-            scope.finish();
-            return;
-        }
-
-        std::unordered_set<std::string_view> seen_keys;
-        seen_keys.reserve(object.size());
         for (const auto& [key, child] : object) {
             require_json_key_length(key, _options.max_json_key_length);
-            if (seen_keys.emplace(key).second) {
-                scope.add_key(to_string_ref(key));
-                collect(child, depth + 1);
-            } else {
-                validate_ignored(child, depth + 1);
-            }
+            scope.add_key(to_string_ref(key));
+            collect(child, depth + 1);
         }
         scope.finish();
     }
 
-    void validate_ignored(SimdJSONParser::Element element, uint32_t depth) 
const {
-        variant_json::require_json_depth(depth);
-        if (element.isArray()) {
-            for (SimdJSONParser::Element child : element.getArray()) {
-                validate_ignored(child, depth + 1);
-            }
-        } else if (element.isObject()) {
-            for (const auto& [key, child] : element.getObject()) {
-                require_json_key_length(key, _options.max_json_key_length);
-                validate_ignored(child, depth + 1);
-            }
-        }
-    }
-
     VariantBatchBuilder::Row& _builder;
     const JsonToVariantOptions& _options;
 };
@@ -385,9 +354,7 @@ FormattedScalar format_json_uuid(const std::array<uint8_t, 
16>& value) {
 } // namespace variant_json
 
 JsonToVariantOptions JsonToVariantOptions::current_config() {
-    return {.max_json_key_length = 
static_cast<uint32_t>(config::variant_max_json_key_length),
-            .throw_on_invalid_json = 
config::variant_throw_exeception_on_invalid_json,
-            .check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check};
+    return {.max_json_key_length = 
static_cast<uint32_t>(config::variant_max_json_key_length)};
 }
 
 struct JsonStringToVariantEncoder::Impl {
@@ -417,15 +384,8 @@ struct JsonStringToVariantEncoder::Impl {
             throw Exception(ErrorCode::INVALID_ARGUMENT,
                             "Variant JSON input has a null data pointer");
         }
-        if (json.size == 0) {
-            auto object = row.start_object();
-            object.finish();
-            row.finish();
-            return;
-        }
-
         SimdJSONParser::Element root;
-        if (!parser.parse(json.data, json.size, root)) {
+        if (json.size == 0 || !parser.parse(json.data, json.size, root)) {
             if (options.throw_on_invalid_json) {
                 throw Exception(ErrorCode::INVALID_ARGUMENT, "Failed to parse 
JSON as Variant");
             }
diff --git a/be/src/exprs/function/parse/variant_string_parse.h 
b/be/src/exprs/function/parse/variant_string_parse.h
index 8fe10f73b64..a2e8fc75bde 100644
--- a/be/src/exprs/function/parse/variant_string_parse.h
+++ b/be/src/exprs/function/parse/variant_string_parse.h
@@ -41,8 +41,10 @@ struct VariantJsonFormatOptions {
 
 struct JsonToVariantOptions {
     uint32_t max_json_key_length = 255;
-    bool throw_on_invalid_json = false;
-    bool check_duplicate_json_path = false;
+    // Text that is not a JSON document, including an empty string, fails the 
row. The Variant
+    // serde turns this off because it mostly re-reads JSON that a Variant 
serde wrote: a value the
+    // parser cannot read back, such as an integer beyond 64 bits, then keeps 
its text.
+    bool throw_on_invalid_json = true;
 
     // Takes a value snapshot. Later changes to mutable config do not affect 
an encoder.
     static JsonToVariantOptions current_config();
diff --git a/be/src/storage/segment/variant/v2/variant_shredder.cpp 
b/be/src/storage/segment/variant/v2/variant_shredder.cpp
index f197d96d30a..cc4c7ebd8d8 100644
--- a/be/src/storage/segment/variant/v2/variant_shredder.cpp
+++ b/be/src/storage/segment/variant/v2/variant_shredder.cpp
@@ -161,16 +161,11 @@ struct VariantShredder::Impl {
         PathState& path_state = paths[path_index];
         const size_t row_marker = row + 1;
         if (path_state.last_row_marker == row_marker) {
-            if (!options.check_duplicate_json_path) {
-                return Status::InvalidArgument("may contains duplicated entry 
: {}",
-                                               path_state.path.get_path());
-            }
-            return Status::OK();
+            return Status::InvalidArgument("may contains duplicated entry : 
{}",
+                                           path_state.path.get_path());
         }
         path_state.last_row_marker = row_marker;
-        if (value.is_null()) {
-            return Status::OK();
-        }
+        DCHECK(!value.is_null());
         return get_or_create_builder(path_index)->append(value, row);
     }
 
@@ -213,9 +208,9 @@ struct VariantShredder::Impl {
 
     Status visit(VariantRef value, MetadataPathCache& metadata_cache, 
PathIndex path_index,
                  size_t row) {
+        // A null member occupies no path, so {"a":{"b":null},"a.b":3} does 
not collide.
         if (value.is_null()) {
-            return options.check_duplicate_json_path ? append_leaf(value, 
path_index, row)
-                                                     : Status::OK();
+            return Status::OK();
         }
         if (value.basic_type() != VariantBasicType::OBJECT) {
             return append_leaf(value, path_index, row);
diff --git a/be/src/storage/segment/variant/v2/variant_shredder.h 
b/be/src/storage/segment/variant/v2/variant_shredder.h
index 91b8c8b4944..b9bbb14daf9 100644
--- a/be/src/storage/segment/variant/v2/variant_shredder.h
+++ b/be/src/storage/segment/variant/v2/variant_shredder.h
@@ -54,7 +54,6 @@ struct VariantShredderOptions {
             BeConsts::DEFAULT_VARIANT_MAX_SPARSE_COLUMN_STATS_SIZE;
     uint32_t doc_bucket_count = 1;
     size_t doc_materialization_min_rows = 0;
-    bool check_duplicate_json_path = false;
 };
 
 struct VariantShreddedColumns {
diff --git a/be/src/storage/segment/variant/variant_writer_helpers.cpp 
b/be/src/storage/segment/variant/variant_writer_helpers.cpp
index 4f8c57c3ae7..d8e53e405b2 100644
--- a/be/src/storage/segment/variant/variant_writer_helpers.cpp
+++ b/be/src/storage/segment/variant/variant_writer_helpers.cpp
@@ -25,7 +25,6 @@
 #include <utility>
 
 #include "common/cast_set.h"
-#include "common/config.h"
 #include "common/exception.h"
 #include "core/assert_cast.h"
 #include "core/column/column_nullable.h"
@@ -86,7 +85,6 @@ Status make_variant_shredder_options(const TabletSchema& 
tablet_schema,
                     cast_set<uint32_t>(std::max(1, 
parent_column.variant_doc_hash_shard_count())),
             .doc_materialization_min_rows = cast_set<size_t>(
                     std::max<int64_t>(0, 
parent_column.variant_doc_materialization_min_rows())),
-            .check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check,
     };
     *options = std::move(result);
     return Status::OK();
diff --git a/be/src/util/json/json_parser.cpp b/be/src/util/json/json_parser.cpp
index 6b814e72028..0999a5bbcd8 100644
--- a/be/src/util/json/json_parser.cpp
+++ b/be/src/util/json/json_parser.cpp
@@ -93,7 +93,9 @@ template <typename ParserImpl>
 void JSONDataParser<ParserImpl>::appendValueIfNotDuplicate(ParseContext& ctx,
                                                            const 
PathInData::Parts& path,
                                                            Field&& value) {
-    if (ctx.check_duplicate_json_path) {
+    // A JSON null occupies no path, so it neither hides nor is hidden by a 
later value: the
+    // first non-null value of a path wins.
+    if (ctx.check_duplicate_json_path && !value.is_null()) {
         PathInData path_in_data(path);
         if (!ctx.visited_path_names.emplace(path_in_data.get_path()).second) {
             return;
diff --git a/be/src/util/json/json_parser.h b/be/src/util/json/json_parser.h
index c4a165e8995..42e0d6fcb31 100644
--- a/be/src/util/json/json_parser.h
+++ b/be/src/util/json/json_parser.h
@@ -101,7 +101,11 @@ void writeValueAsJsonb(const Element& element, 
JsonbWriter& writer) {
 
 struct ParseConfig {
     bool deprecated_enable_flatten_nested = false;
-    bool check_duplicate_json_path = false;
+    // Duplicate paths in one JSON document are always rejected.
+    bool check_duplicate_json_path = true;
+    // Text that is not a JSON document keeps its text, like the CAST and load 
paths expect. Only
+    // parse_to_variant() turns this on.
+    bool throw_on_invalid_json = false;
     enum class ParseTo {
         OnlySubcolumns = 0,
         OnlyDocValueColumn = 1,
diff --git a/be/test/core/column/column_variant_v2_test.cpp 
b/be/test/core/column/column_variant_v2_test.cpp
index fa74c056386..c774a4d7570 100644
--- a/be/test/core/column/column_variant_v2_test.cpp
+++ b/be/test/core/column/column_variant_v2_test.cpp
@@ -80,9 +80,7 @@ namespace {
 using MetaIdsColumn = ColumnVector<TYPE_UINT32>;
 
 VariantField encode_json(std::string_view json) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder({.max_json_key_length = 255, 
.throw_on_invalid_json = true});
     encoder.add_json({json.data(), json.size()});
     VariantBatchBuilder block = encoder.finish_batch();
     return VariantField::from_ref(block.value_at(0));
@@ -1521,9 +1519,8 @@ TEST(ColumnVariantV2Test, 
InsertsCodecOwnedBatchesDirectly) {
     }
 
     {
-        JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                            .throw_on_invalid_json = true,
-                                            .check_duplicate_json_path = 
false});
+        JsonStringToVariantEncoder encoder(
+                {.max_json_key_length = 255, .throw_on_invalid_json = true});
         encoder.add_json(StringRef("7", 1));
         VariantBatchBuilder block = encoder.finish_batch();
         auto column = ColumnVariantV2::create();
@@ -1533,9 +1530,8 @@ TEST(ColumnVariantV2Test, 
InsertsCodecOwnedBatchesDirectly) {
     }
 
     {
-        JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                            .throw_on_invalid_json = true,
-                                            .check_duplicate_json_path = 
false});
+        JsonStringToVariantEncoder encoder(
+                {.max_json_key_length = 255, .throw_on_invalid_json = true});
         constexpr std::string_view FIRST = R"({"a":[1,{"b":true}]})";
         constexpr std::string_view SECOND = R"({"b":2,"a":[]})";
         encoder.add_json({FIRST.data(), FIRST.size()});
diff --git a/be/test/core/data_type_serde/data_type_serde_arrow_test.cpp 
b/be/test/core/data_type_serde/data_type_serde_arrow_test.cpp
index f2551229706..b56dda3f225 100644
--- a/be/test/core/data_type_serde/data_type_serde_arrow_test.cpp
+++ b/be/test/core/data_type_serde/data_type_serde_arrow_test.cpp
@@ -940,9 +940,8 @@ TEST(DataTypeSerDeArrowTest, 
PlainArrowConverterDoesNotInferIcebergUuid) {
 
 TEST(DataTypeSerDeArrowTest, IcebergVariantExtensionAndParquetSchema) {
     auto make_variant_column = []() {
-        JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                            .throw_on_invalid_json = true,
-                                            .check_duplicate_json_path = 
false});
+        JsonStringToVariantEncoder encoder(
+                {.max_json_key_length = 1024, .throw_on_invalid_json = true});
         for (std::string_view json :
              {std::string_view {R"({"name":"doris","n":1})"}, std::string_view 
{"null"},
               std::string_view {R"([1,true,"x"])"}}) {
@@ -1037,9 +1036,8 @@ TEST(DataTypeSerDeArrowTest, 
IcebergVariantExtensionAndParquetSchema) {
 
 TEST(DataTypeSerDeArrowTest, NestedIcebergVariantExtensionsAndParquetSchema) {
     auto make_variant_column = [](std::initializer_list<std::string_view> 
json_values) {
-        JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                            .throw_on_invalid_json = true,
-                                            .check_duplicate_json_path = 
false});
+        JsonStringToVariantEncoder encoder(
+                {.max_json_key_length = 1024, .throw_on_invalid_json = true});
         for (std::string_view json : json_values) {
             encoder.add_json({json.data(), json.size()});
         }
diff --git 
a/be/test/core/data_type_serde/data_type_variant_v2_serde_binary_roundtrip_test.cpp
 
b/be/test/core/data_type_serde/data_type_variant_v2_serde_binary_roundtrip_test.cpp
index fbe40886df2..f7dc4e171ed 100644
--- 
a/be/test/core/data_type_serde/data_type_variant_v2_serde_binary_roundtrip_test.cpp
+++ 
b/be/test/core/data_type_serde/data_type_variant_v2_serde_binary_roundtrip_test.cpp
@@ -63,9 +63,7 @@ namespace doris {
 namespace {
 
 VariantField encode_json(std::string_view json) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder({.max_json_key_length = 255, 
.throw_on_invalid_json = true});
     encoder.add_json({json.data(), json.size()});
     VariantBatchBuilder block = encoder.finish_batch();
     return VariantField::from_ref(block.value_at(0));
diff --git 
a/be/test/core/data_type_serde/data_type_variant_v2_serde_input_test.cpp 
b/be/test/core/data_type_serde/data_type_variant_v2_serde_input_test.cpp
index e9d3d669a17..6e8d4718a70 100644
--- a/be/test/core/data_type_serde/data_type_variant_v2_serde_input_test.cpp
+++ b/be/test/core/data_type_serde/data_type_variant_v2_serde_input_test.cpp
@@ -22,7 +22,6 @@
 #include <string_view>
 #include <vector>
 
-#include "common/config.h"
 #include "core/column/column_nullable.h"
 #include "core/column/column_string.h"
 #include "core/column/column_vector.h"
@@ -37,18 +36,6 @@
 namespace doris {
 namespace {
 
-class ScopedInvalidJsonMode {
-public:
-    explicit ScopedInvalidJsonMode(bool value)
-            : _old(config::variant_throw_exeception_on_invalid_json) {
-        config::variant_throw_exeception_on_invalid_json = value;
-    }
-    ~ScopedInvalidJsonMode() { 
config::variant_throw_exeception_on_invalid_json = _old; }
-
-private:
-    bool _old;
-};
-
 Status deserialize_json(const DataTypeVariantV2SerDe& serde, ColumnVariantV2& 
column,
                         std::string_view text) {
     Slice slice(text.data(), text.size());
@@ -91,30 +78,26 @@ ColumnVariantV2::MutablePtr typed_int(int32_t value) {
 TEST(DataTypeVariantV2SerdeInputTest, JsonUsesT15ValidEmptyAndInvalidPolicies) 
{
     DataTypeVariantV2SerDe serde;
     auto column = ColumnVariantV2::create();
-    {
-        ScopedInvalidJsonMode mode(false);
-        EXPECT_TRUE(deserialize_json(serde, *column, 
R"({"b":[1,null]})").ok());
-        EXPECT_TRUE(deserialize_json(serde, *column, {}).ok());
-        EXPECT_TRUE(deserialize_json(serde, *column, "not-json").ok());
-    }
-    ASSERT_EQ(column->size(), 3);
+    // The serde re-reads JSON that it wrote, so text the parser rejects keeps 
its text instead of
+    // failing, for example an integer beyond 64 bits in a serialized 
aggregate state.
+    EXPECT_TRUE(deserialize_json(serde, *column, R"({"b":[1,null]})").ok());
+    EXPECT_TRUE(deserialize_json(serde, *column, {}).ok());
+    EXPECT_TRUE(deserialize_json(serde, *column, "not-json").ok());
+    EXPECT_TRUE(deserialize_json(serde, *column, "18446744073709551616").ok());
+    ASSERT_EQ(column->size(), 4);
     EXPECT_EQ(json_at(serde, *column, 0), R"({"b":[1,null]})");
-    EXPECT_EQ(json_at(serde, *column, 1), "{}");
+    EXPECT_EQ(json_at(serde, *column, 1), R"("")");
     EXPECT_EQ(json_at(serde, *column, 2), R"("not-json")");
+    EXPECT_EQ(json_at(serde, *column, 3), R"("18446744073709551616")");
 
-    const size_t before = column->size();
-    {
-        ScopedInvalidJsonMode mode(true);
-        EXPECT_EQ(deserialize_json(serde, *column, "not-json").code(), 
ErrorCode::INVALID_ARGUMENT);
-    }
-    EXPECT_EQ(column->size(), before);
+    const std::string long_key(300, 'k');
+    const std::string long_key_json = R"({")" + long_key + R"(":1})";
+    ASSERT_TRUE(deserialize_json(serde, *column, long_key_json).ok());
+    EXPECT_EQ(json_at(serde, *column, 4), long_key_json);
 
+    const size_t before = column->size();
     const std::string invalid_utf8("\xC3\x28", 2);
-    {
-        ScopedInvalidJsonMode mode(false);
-        EXPECT_EQ(deserialize_json(serde, *column, invalid_utf8).code(),
-                  ErrorCode::INVALID_ARGUMENT);
-    }
+    EXPECT_EQ(deserialize_json(serde, *column, invalid_utf8).code(), 
ErrorCode::INVALID_ARGUMENT);
     EXPECT_EQ(column->size(), before);
 }
 
@@ -125,11 +108,10 @@ TEST(DataTypeVariantV2SerdeInputTest, 
VectorFailureIsAtomicAndCounterIsNotAdvanc
     const size_t before = column->size();
 
     std::string valid = R"({"a":1})";
-    std::string invalid = "{";
+    std::string invalid("\xC3\x28", 2);
     std::vector<Slice> slices {{valid.data(), valid.size()}, {invalid.data(), 
invalid.size()}};
     uint64_t num_deserialized = 0;
     DataTypeSerDe::FormatOptions options;
-    ScopedInvalidJsonMode mode(true);
     const Status status =
             serde.deserialize_column_from_json_vector(*column, slices, 
&num_deserialized, options);
     EXPECT_EQ(status.code(), ErrorCode::INVALID_ARGUMENT);
diff --git 
a/be/test/core/data_type_serde/data_type_variant_v2_serde_jsonb_test.cpp 
b/be/test/core/data_type_serde/data_type_variant_v2_serde_jsonb_test.cpp
index 5cecf9d9cef..a88aeec2d48 100644
--- a/be/test/core/data_type_serde/data_type_variant_v2_serde_jsonb_test.cpp
+++ b/be/test/core/data_type_serde/data_type_variant_v2_serde_jsonb_test.cpp
@@ -112,9 +112,8 @@ std::string json_at(const DataTypeVariantV2SerDe& serde, 
const IColumn& column,
 }
 
 ColumnVariantV2::MutablePtr 
encoded_json(std::initializer_list<std::string_view> rows) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder(
+            {.max_json_key_length = 1024, .throw_on_invalid_json = true});
     for (std::string_view row : rows) {
         encoder.add_json({row.data(), row.size()});
     }
diff --git 
a/be/test/core/data_type_serde/data_type_variant_v2_serde_output_test.cpp 
b/be/test/core/data_type_serde/data_type_variant_v2_serde_output_test.cpp
index 25c3ca7abd9..fa5691fc629 100644
--- a/be/test/core/data_type_serde/data_type_variant_v2_serde_output_test.cpp
+++ b/be/test/core/data_type_serde/data_type_variant_v2_serde_output_test.cpp
@@ -99,9 +99,8 @@ ColumnPtr encoded_copy(const ColumnVariantV2& typed) {
 }
 
 ColumnVariantV2::MutablePtr 
encoded_json(std::initializer_list<std::string_view> rows) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder(
+            {.max_json_key_length = 1024, .throw_on_invalid_json = true});
     for (std::string_view row : rows) {
         encoder.add_json({row.data(), row.size()});
     }
diff --git 
a/be/test/exprs/function/function_variant_element_v2_encoded_test.cpp 
b/be/test/exprs/function/function_variant_element_v2_encoded_test.cpp
index 585847de4ad..84b1b71bf7d 100644
--- a/be/test/exprs/function/function_variant_element_v2_encoded_test.cpp
+++ b/be/test/exprs/function/function_variant_element_v2_encoded_test.cpp
@@ -35,9 +35,8 @@ namespace {
 using Segment = VariantElementV2PathSegment;
 
 VariantField encode_json(std::string_view json) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder(
+            {.max_json_key_length = 1024, .throw_on_invalid_json = true});
     encoder.add_json({json.data(), json.size()});
     VariantBatchBuilder block = encoder.finish_batch();
     return VariantField::from_ref(block.value_at(0));
diff --git a/be/test/exprs/function/function_variant_parse_test.cpp 
b/be/test/exprs/function/function_variant_parse_test.cpp
index 383329a1b0a..05eb0443a70 100644
--- a/be/test/exprs/function/function_variant_parse_test.cpp
+++ b/be/test/exprs/function/function_variant_parse_test.cpp
@@ -187,7 +187,6 @@ TEST(FunctionVariantParseTest, 
LegacyPathPreservesSqlNullAndErrorToNull) {
 
     const DataTypePtr string_type = std::make_shared<DataTypeString>();
     const std::string invalid_utf8(1, static_cast<char>(0xFF));
-    ScopedValue strict(config::variant_throw_exeception_on_invalid_json, true);
     ExecutionResult failure = execute_parse(
             "parse_to_variant", make_strings({R"({"before":1})", invalid_utf8, 
R"({"after":2})"}),
             string_type, 3, false);
@@ -270,15 +269,22 @@ TEST(FunctionVariantParseTest, 
ConfiguredVariantReturnTypeBuildsAndExecutes) {
 
 TEST(FunctionVariantParseTest, DistinguishesSqlNullJsonNullEmptyAndConst) {
     const DataTypePtr string_type = std::make_shared<DataTypeString>();
-    ExecutionResult values = execute_parse(
-            "parse_to_variant", make_strings({R"({"a":1})", "null", ""}), 
string_type, 3);
+    ExecutionResult values =
+            execute_parse("parse_to_variant", make_strings({R"({"a":1})", 
"null"}), string_type, 2);
     ASSERT_TRUE(values.status.ok()) << values.status.to_string();
-    ASSERT_EQ(values.output->size(), 3);
+    ASSERT_EQ(values.output->size(), 2);
     EXPECT_FALSE(is_sql_null_at(values.output, 0));
     EXPECT_FALSE(is_sql_null_at(values.output, 1));
     EXPECT_EQ(variant_json_at(values.output, 0), R"({"a":1})");
     EXPECT_EQ(variant_json_at(values.output, 1), "null");
-    EXPECT_EQ(variant_json_at(values.output, 2), "{}");
+
+    // An empty string is not a JSON document.
+    ExecutionResult empty = execute_parse("parse_to_variant", 
make_strings({""}), string_type, 1);
+    EXPECT_EQ(empty.status.code(), ErrorCode::INVALID_ARGUMENT) << 
empty.status.to_string();
+    ExecutionResult empty_to_null =
+            execute_parse("try_parse_to_variant", make_strings({""}), 
string_type, 1);
+    ASSERT_TRUE(empty_to_null.status.ok()) << empty_to_null.status.to_string();
+    EXPECT_TRUE(is_sql_null_at(empty_to_null.output, 0));
 
     const DataTypePtr nullable_string_type = 
make_nullable(std::make_shared<DataTypeString>());
     ExecutionResult nullable = execute_parse(
@@ -301,7 +307,6 @@ TEST(FunctionVariantParseTest, 
DistinguishesSqlNullJsonNullEmptyAndConst) {
 }
 
 TEST(FunctionVariantParseTest, StrictFailureDoesNotPublishPartialBatch) {
-    ScopedValue strict(config::variant_throw_exeception_on_invalid_json, true);
     const DataTypePtr string_type = std::make_shared<DataTypeString>();
     ExecutionResult result =
             execute_parse("parse_to_variant",
@@ -319,26 +324,17 @@ TEST(FunctionVariantParseTest, 
StrictFailureDoesNotPublishPartialBatch) {
 
 TEST(FunctionVariantParseTest, ErrorToNullOnlyNullsRecoverableFailures) {
     const DataTypePtr string_type = std::make_shared<DataTypeString>();
-    {
-        ScopedValue strict(config::variant_throw_exeception_on_invalid_json, 
true);
-        ExecutionResult result = execute_parse(
-                "try_parse_to_variant",
-                make_strings({R"({"before":1})", "{", "null", 
R"({"after":2})"}), string_type, 4);
-        ASSERT_TRUE(result.status.ok()) << result.status.to_string();
-        EXPECT_FALSE(is_sql_null_at(result.output, 0));
-        EXPECT_TRUE(is_sql_null_at(result.output, 1));
-        EXPECT_FALSE(is_sql_null_at(result.output, 2));
-        EXPECT_EQ(variant_json_at(result.output, 2), "null");
-        EXPECT_EQ(variant_json_at(result.output, 3), R"({"after":2})");
-    }
-    {
-        ScopedValue 
permissive(config::variant_throw_exeception_on_invalid_json, false);
-        ExecutionResult result =
-                execute_parse("try_parse_to_variant", make_strings({"{"}), 
string_type, 1);
-        ASSERT_TRUE(result.status.ok()) << result.status.to_string();
-        EXPECT_FALSE(is_sql_null_at(result.output, 0));
-        EXPECT_EQ(variant_json_at(result.output, 0), R"("{")");
-    }
+    ExecutionResult result =
+            execute_parse("try_parse_to_variant",
+                          make_strings({R"({"before":1})", "{", "null", 
"hello", R"({"after":2})"}),
+                          string_type, 5);
+    ASSERT_TRUE(result.status.ok()) << result.status.to_string();
+    EXPECT_FALSE(is_sql_null_at(result.output, 0));
+    EXPECT_TRUE(is_sql_null_at(result.output, 1));
+    EXPECT_FALSE(is_sql_null_at(result.output, 2));
+    EXPECT_EQ(variant_json_at(result.output, 2), "null");
+    EXPECT_TRUE(is_sql_null_at(result.output, 3));
+    EXPECT_EQ(variant_json_at(result.output, 4), R"({"after":2})");
 }
 
 TEST(FunctionVariantParseTest, ConfiguredInputValidationUsesFailOrOuterNull) {
@@ -355,7 +351,6 @@ TEST(FunctionVariantParseTest, 
ConfiguredInputValidationUsesFailOrOuterNull) {
         EXPECT_TRUE(is_sql_null_at(null.output, 0));
     }
     {
-        ScopedValue 
reject_duplicates(config::variant_enable_duplicate_json_path_check, false);
         ExecutionResult fail = execute_parse("parse_to_variant", 
make_strings({R"({"a":1,"a":2})"}),
                                              string_type, 1);
         EXPECT_FALSE(fail.status.ok());
@@ -365,15 +360,6 @@ TEST(FunctionVariantParseTest, 
ConfiguredInputValidationUsesFailOrOuterNull) {
         EXPECT_TRUE(is_sql_null_at(null.output, 0));
     }
     {
-        ScopedValue 
keep_first(config::variant_enable_duplicate_json_path_check, true);
-        ExecutionResult result = execute_parse("try_parse_to_variant",
-                                               
make_strings({R"({"a":1,"a":2})"}), string_type, 1);
-        ASSERT_TRUE(result.status.ok()) << result.status.to_string();
-        EXPECT_FALSE(is_sql_null_at(result.output, 0));
-        EXPECT_EQ(variant_json_at(result.output, 0), R"({"a":1})");
-    }
-    {
-        ScopedValue 
permissive(config::variant_throw_exeception_on_invalid_json, false);
         const std::string invalid_utf8(1, static_cast<char>(0xFF));
         ExecutionResult fail =
                 execute_parse("parse_to_variant", 
make_strings({invalid_utf8}), string_type, 1);
@@ -383,6 +369,17 @@ TEST(FunctionVariantParseTest, 
ConfiguredInputValidationUsesFailOrOuterNull) {
         ASSERT_TRUE(null.status.ok()) << null.status.to_string();
         EXPECT_TRUE(is_sql_null_at(null.output, 0));
     }
+    {
+        // The DOM parser cannot read an integer beyond 64 bits, so the 
document is invalid JSON.
+        ExecutionResult fail = execute_parse(
+                "parse_to_variant", make_strings({"18446744073709551616"}), 
string_type, 1);
+        EXPECT_FALSE(fail.status.ok());
+        ExecutionResult null =
+                execute_parse("try_parse_to_variant",
+                              make_strings({R"({"n":18446744073709551616})"}), 
string_type, 1);
+        ASSERT_TRUE(null.status.ok()) << null.status.to_string();
+        EXPECT_TRUE(is_sql_null_at(null.output, 0));
+    }
     {
         const std::string too_deep = 
nested_array_json(VARIANT_MAX_NESTING_DEPTH + 1);
         ExecutionResult fail =
diff --git a/be/test/exprs/variant_v2_execution_test.cpp 
b/be/test/exprs/variant_v2_execution_test.cpp
index 36fd2e1bec9..284ada616b9 100644
--- a/be/test/exprs/variant_v2_execution_test.cpp
+++ b/be/test/exprs/variant_v2_execution_test.cpp
@@ -50,9 +50,8 @@ TEST(VariantV2ExecutionTest, 
TypePropertiesDoNotAffectEquality) {
 
 TEST(VariantV2ExecutionTest, CanonicalComparison) {
     auto parse = [](std::initializer_list<std::string_view> rows) {
-        JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                            .throw_on_invalid_json = true,
-                                            .check_duplicate_json_path = 
false});
+        JsonStringToVariantEncoder encoder(
+                {.max_json_key_length = 255, .throw_on_invalid_json = true});
         for (auto json : rows) {
             encoder.add_json({json.data(), json.size()});
         }
diff --git a/be/test/format/transformer/vparquet_writer_test.cpp 
b/be/test/format/transformer/vparquet_writer_test.cpp
index cfdf4069aae..3b66c261b28 100644
--- a/be/test/format/transformer/vparquet_writer_test.cpp
+++ b/be/test/format/transformer/vparquet_writer_test.cpp
@@ -91,9 +91,8 @@ TEST_F(VParquetWriterTest, 
WritesIcebergVariantAndCollectsLogicalMetrics) {
                                       options, &schema_json, *schema);
     ASSERT_TRUE(transformer.open().ok());
 
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder(
+            {.max_json_key_length = 1024, .throw_on_invalid_json = true});
     for (std::string_view json : {std::string_view 
{R"({"name":"doris","n":1})"},
                                   std::string_view {"null"}, std::string_view 
{R"([1,2,3])"}}) {
         encoder.add_json({json.data(), json.size()});
@@ -178,9 +177,8 @@ TEST_F(VParquetWriterTest, WritesNestedIcebergVariant) {
                                       options, &schema_json, *schema);
     ASSERT_TRUE(transformer.open().ok());
 
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 1024,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder(
+            {.max_json_key_length = 1024, .throw_on_invalid_json = true});
     for (std::string_view json :
          {std::string_view {R"({"kind":"nested"})"}, std::string_view {"null"},
           std::string_view {"{}"}, std::string_view {"7"}}) {
diff --git a/be/test/storage/variant/variant_column_writer_reader_test.cpp 
b/be/test/storage/variant/variant_column_writer_reader_test.cpp
index 6e05e1cae7f..7e8d1bbd326 100644
--- a/be/test/storage/variant/variant_column_writer_reader_test.cpp
+++ b/be/test/storage/variant/variant_column_writer_reader_test.cpp
@@ -105,20 +105,6 @@ static std::string variant_writer_test_name(
     return variant_writer_input_name(info.param);
 }
 
-class ScopedDuplicateJsonPathCheck {
-public:
-    explicit ScopedDuplicateJsonPathCheck(bool enabled)
-            : _old_value(config::variant_enable_duplicate_json_path_check) {
-        config::variant_enable_duplicate_json_path_check = enabled;
-    }
-    ~ScopedDuplicateJsonPathCheck() {
-        config::variant_enable_duplicate_json_path_check = _old_value;
-    }
-
-private:
-    bool _old_value;
-};
-
 static Status create_variant_writer_source(VariantWriterInput input,
                                            const std::vector<std::string>& 
jsons,
                                            int max_subcolumns_count, bool 
enable_doc_mode,
@@ -138,7 +124,6 @@ static Status 
create_variant_writer_source(VariantWriterInput input,
         ParseConfig parse_config;
         parse_config.parse_to = enable_doc_mode ? 
ParseConfig::ParseTo::OnlyDocValueColumn
                                                 : 
ParseConfig::ParseTo::OnlySubcolumns;
-        parse_config.check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check;
         variant_util::parse_json_to_variant(*variant, *json_column, 
parse_config);
         values = std::move(variant);
         type = std::make_shared<DataTypeVariant>(max_subcolumns_count, 
enable_doc_mode);
@@ -2299,7 +2284,6 @@ TEST_P(VariantWriterCompatibilityTest, 
materialized_array_preserves_middle_row_g
 }
 
 TEST_P(VariantWriterCompatibilityTest, 
dotted_and_nested_paths_follow_writer_semantics) {
-    ScopedDuplicateJsonPathCheck duplicate_path_check(false);
     init_variant_tablet(10015 + static_cast<int>(GetParam()), 2);
 
     const std::vector<std::string> jsons {
@@ -2318,14 +2302,6 @@ TEST_P(VariantWriterCompatibilityTest, 
dotted_and_nested_paths_follow_writer_sem
             "shared_cross_row_dotted_" + variant_writer_input_name(GetParam());
     const Status write_status =
             write_variant_segment(source, source_type, rowset_id, &footer, 
&file_path);
-    if (GetParam() == VariantWriterInput::V1) {
-        // Preserve the legacy behavior when duplicate-path checking is 
disabled: V1 does not
-        // canonicalize the plain dotted key during parse and rejects the 
conflicting paths later.
-        EXPECT_EQ(write_status.code(), ErrorCode::INVALID_JSON_PATH) << 
write_status;
-        EXPECT_NE(write_status.to_string().find("duplicated entry : a.b"), 
std::string::npos)
-                << write_status;
-        return;
-    }
     ASSERT_TRUE(write_status.ok()) << write_status;
     VariantStorageParseWriteResult footer_stats;
     collect_variant_footer_stats(footer, 0, &footer_stats);
@@ -2340,11 +2316,15 @@ TEST_P(VariantWriterCompatibilityTest, 
dotted_and_nested_paths_follow_writer_sem
                       }));
 }
 
-TEST_P(VariantWriterCompatibilityTest, 
dotted_null_path_is_first_when_duplicate_check_enabled) {
-    ScopedDuplicateJsonPathCheck duplicate_path_check(true);
+TEST_P(VariantWriterCompatibilityTest, 
dotted_and_nested_paths_without_collision_are_written) {
     init_variant_tablet(10019 + static_cast<int>(GetParam()), 2);
 
-    const std::vector<std::string> jsons {R"({"a":{"b":null},"a.b":5})"};
+    // A null member occupies no path, and a dotted key whose children differ 
from the nested
+    // object's children reaches different paths, so neither row collides.
+    const std::vector<std::string> jsons {
+            R"({"a.b":null,"a":{"b":5}})",
+            R"({"a.b":{"c":8},"a":{"b":{"d":9}}})",
+    };
     ColumnPtr source;
     DataTypePtr source_type;
     ASSERT_TRUE(create_variant_writer_source(GetParam(), jsons, 2, false, {}, 
&source, &source_type)
@@ -2353,12 +2333,17 @@ TEST_P(VariantWriterCompatibilityTest, 
dotted_null_path_is_first_when_duplicate_
     SegmentFooterPB footer;
     std::string file_path;
     const std::string rowset_id =
-            "shared_dotted_null_first_" + 
variant_writer_input_name(GetParam());
-    ASSERT_TRUE(write_variant_segment(source, source_type, rowset_id, &footer, 
&file_path).ok());
+            "shared_dotted_without_collision_" + 
variant_writer_input_name(GetParam());
+    const Status write_status =
+            write_variant_segment(source, source_type, rowset_id, &footer, 
&file_path);
+    ASSERT_TRUE(write_status.ok()) << write_status;
 
     std::vector<std::optional<std::string>> actual;
     ASSERT_TRUE(read_variant_root_rows(footer, file_path, &actual).ok());
-    EXPECT_EQ(actual, (std::vector<std::optional<std::string>> {"{}"}));
+    EXPECT_EQ(actual, (std::vector<std::optional<std::string>> {
+                              R"({"a":{"b":5}})",
+                              R"({"a":{"b":{"c":8,"d":9}}})",
+                      }));
 }
 
 TEST_P(VariantWriterCompatibilityTest, nullable_round_trip) {
@@ -2440,47 +2425,7 @@ TEST_P(VariantWriterCompatibilityTest, 
doc_mode_round_trip) {
     }
 }
 
-TEST_F(VariantColumnWriterReaderTest, 
test_write_column_variant_v2_duplicate_dotted_paths) {
-    ScopedDuplicateJsonPathCheck duplicate_path_check(true);
-    init_variant_tablet(10003, 2);
-
-    const std::vector<std::string> jsons {
-            R"({"a.b":1,"a":{"b":2}})",
-            R"({"a":{"b":3},"a.b":4})",
-            R"({"a.b":null,"a":{"b":5}})",
-            R"({"a.b":6})",
-            R"({"a":{"b":7}})",
-            R"({"a.b":{"c":8},"a":{"b":{"d":9}}})",
-    };
-    auto source = ColumnVariantV2::create();
-    DataTypeVariantV2SerDe serde;
-    DataTypeSerDe::FormatOptions serde_options;
-    for (const auto& json : jsons) {
-        Slice slice(json.data(), json.size());
-        ASSERT_TRUE(serde.deserialize_one_cell_from_json(*source, slice, 
serde_options).ok());
-    }
-
-    SegmentFooterPB footer;
-    std::string file_path;
-    const auto source_type = std::make_shared<DataTypeVariantV2>(2, false);
-    const Status write_status = write_variant_segment(source->get_ptr(), 
source_type,
-                                                      "v2_duplicate_paths", 
&footer, &file_path, 3);
-    ASSERT_TRUE(write_status.ok()) << write_status;
-
-    std::vector<std::optional<std::string>> actual;
-    ASSERT_TRUE(read_variant_root_rows(footer, file_path, &actual).ok());
-    // ColumnVariantV2 stores object entries in metadata field-id order, so 
the nested form is the
-    // first canonical leaf for a dotted-path collision regardless of the 
source JSON key order.
-    const std::vector<std::optional<std::string>> expected {
-            R"({"a":{"b":2}})", R"({"a":{"b":3}})", R"({"a":{"b":5}})",
-            R"({"a":{"b":6}})", R"({"a":{"b":7}})", 
R"({"a":{"b":{"c":8,"d":9}}})",
-    };
-    EXPECT_EQ(actual, expected);
-}
-
-TEST_F(VariantColumnWriterReaderTest,
-       
test_write_column_variant_v2_rejects_duplicate_dotted_paths_without_check) {
-    ScopedDuplicateJsonPathCheck duplicate_path_check(false);
+TEST_F(VariantColumnWriterReaderTest, 
test_write_column_variant_v2_rejects_duplicate_dotted_paths) {
     init_variant_tablet(10008, 2);
 
     auto source = ColumnVariantV2::create();
@@ -3322,7 +3267,6 @@ TEST_F(VariantColumnWriterReaderTest, 
v2_shredder_uses_only_rows_in_requested_ra
     segment_v2::VariantShredder shredder({
             .max_subcolumns_count = 1,
             .sparse_bucket_count = 1,
-            .check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check,
     });
     ASSERT_TRUE(shredder.append(combined->read_view(), 1, 1).ok());
     segment_v2::VariantShreddedColumns shredded;
@@ -3399,7 +3343,6 @@ TEST_F(VariantColumnWriterReaderTest, 
v2_shredder_drops_typed_cast_null_from_spa
             .max_subcolumns_count = 1,
             .typed_paths_to_sparse = true,
             .sparse_bucket_count = 1,
-            .check_duplicate_json_path = 
config::variant_enable_duplicate_json_path_check,
     });
     ASSERT_TRUE(shredder.append(source->read_view(), 0, source->size()).ok());
     segment_v2::VariantShreddedColumns shredded;
diff --git a/be/test/storage/variant/variant_util_test.cpp 
b/be/test/storage/variant/variant_util_test.cpp
index fb729a3cfd5..5ccfdcd7da3 100644
--- a/be/test/storage/variant/variant_util_test.cpp
+++ b/be/test/storage/variant/variant_util_test.cpp
@@ -120,20 +120,6 @@ static std::string _serialize_variant_row(const 
ColumnVariant& variant, size_t r
     return value;
 }
 
-class ScopedDuplicateJsonPathCheck {
-public:
-    explicit ScopedDuplicateJsonPathCheck(bool value)
-            : _old_value(config::variant_enable_duplicate_json_path_check) {
-        config::variant_enable_duplicate_json_path_check = value;
-    }
-    ~ScopedDuplicateJsonPathCheck() {
-        config::variant_enable_duplicate_json_path_check = _old_value;
-    }
-
-private:
-    bool _old_value;
-};
-
 class ScopedVariantStorageParseMode {
 public:
     explicit ScopedVariantStorageParseMode(int32_t value)
@@ -365,7 +351,6 @@ TEST(VariantUtilTest, 
ParseOnlyDocValueColumn_SerializesMixedTypes) {
 }
 
 TEST(VariantUtilTest, ParseDuplicateJsonPathsKeepsFirstValue) {
-    ScopedDuplicateJsonPathCheck check_guard(true);
     const std::vector<std::string_view> jsons = {
             R"({"a":42,"a":{"b":42}})", R"({"a":123,"a":"123"})",       
R"({"a.b":1,"a":{"b":2}})",
             R"({"a":{"b":3},"a.b":4})", R"({"a":{"b":5},"a":{"c":6}})",
@@ -417,7 +402,6 @@ TEST(VariantUtilTest, 
ParseDuplicateJsonPathsKeepsFirstValue) {
 }
 
 TEST(VariantUtilTest, ParseDuplicateJsonPathsKeepsFirstArrayOrScalarValue) {
-    ScopedDuplicateJsonPathCheck check_guard(true);
     const std::vector<std::string_view> jsons = {
             R"({"a":[1],"a":2})",
             R"({"a":2,"a":[1]})",
@@ -449,7 +433,6 @@ TEST(VariantUtilTest, 
ParseDuplicateJsonPathsKeepsFirstArrayOrScalarValue) {
 }
 
 TEST(VariantUtilTest, ParseDuplicateJsonPathsInDocModeKeepsFirstValue) {
-    ScopedDuplicateJsonPathCheck check_guard(true);
     const std::vector<std::string_view> jsons = {
             R"({"a":42,"a":{"b":42}})", R"({"a":123,"a":"123"})",       
R"({"a.b":1,"a":{"b":2}})",
             R"({"a":{"b":3},"a.b":4})", R"({"a":{"b":5},"a":{"c":6}})",
@@ -506,7 +489,6 @@ TEST(VariantUtilTest, 
ParseDuplicateJsonPathsInDocModeKeepsFirstValue) {
 }
 
 TEST(VariantUtilTest, 
ParseDuplicateJsonPathsInDocModeKeepsFirstArrayOrScalarValue) {
-    ScopedDuplicateJsonPathCheck check_guard(true);
     const std::vector<std::string_view> jsons = {
             R"({"a":[1],"a":2})",
             R"({"a":2,"a":[1]})",
@@ -540,20 +522,6 @@ TEST(VariantUtilTest, 
ParseDuplicateJsonPathsInDocModeKeepsFirstArrayOrScalarVal
     EXPECT_EQ(JsonbToJson::jsonb_to_json_string(second.get_value(), 
second.get_size()), "2");
 }
 
-TEST(VariantUtilTest, ParseDuplicateJsonPathsCheckDisabledByDefault) {
-    ScopedDuplicateJsonPathCheck check_guard(false);
-    const std::vector<std::string_view> jsons = {
-            R"({"a":123,"a":"123"})",
-    };
-
-    auto variant = ColumnVariant::create(0, false);
-    auto json_col = _make_json_column(jsons);
-
-    ParseConfig cfg;
-    cfg.deprecated_enable_flatten_nested = false;
-    EXPECT_THROW(parse_json_to_variant(*variant, *json_col, cfg), Exception);
-}
-
 TEST(VariantUtilTest, ParseVariantColumns_StorageNonDocScalarJsonToDocValueKv) 
{
     TabletSchema tablet_schema = _make_variant_schema(false);
     std::vector<std::string> jsons {R"({"a":1})", R"({"a":2})"};
diff --git a/be/test/testutil/index_storage_test_util.cpp 
b/be/test/testutil/index_storage_test_util.cpp
index b94a62be2e9..8a17aff2f01 100644
--- a/be/test/testutil/index_storage_test_util.cpp
+++ b/be/test/testutil/index_storage_test_util.cpp
@@ -412,7 +412,6 @@ Status fill_variant_column(const VariantColumnSpec& 
column_spec, const IndexBatc
 
     ParseConfig config;
     config.deprecated_enable_flatten_nested = 
batch.deprecated_enable_flatten_nested;
-    config.check_duplicate_json_path = batch.check_duplicate_json_path;
     config.parse_to =
             column_spec.enable_doc_mode ? 
ParseConfig::ParseTo::OnlyDocValueColumn : batch.parse_to;
     variant_util::parse_json_to_variant(*variant_column, *json_column, config);
diff --git a/be/test/testutil/index_storage_test_util.h 
b/be/test/testutil/index_storage_test_util.h
index 26ea66c2686..f4f10dcc848 100644
--- a/be/test/testutil/index_storage_test_util.h
+++ b/be/test/testutil/index_storage_test_util.h
@@ -116,7 +116,6 @@ struct IndexBatch {
     std::vector<std::vector<std::string>> variant_jsons_by_column;
     std::vector<ColumnPtr> variant_columns_by_column;
     bool deprecated_enable_flatten_nested = false;
-    bool check_duplicate_json_path = false;
     ParseConfig::ParseTo parse_to = ParseConfig::ParseTo::OnlySubcolumns;
 
     static IndexBatch single_text(std::vector<std::string> values, int32_t 
first_key = 0);
diff --git a/be/test/util/variant/variant_field_test.cpp 
b/be/test/util/variant/variant_field_test.cpp
index 4c900dfbdd3..eabdcafb142 100644
--- a/be/test/util/variant/variant_field_test.cpp
+++ b/be/test/util/variant/variant_field_test.cpp
@@ -213,9 +213,7 @@ void expect_encode_and_decode_preservation(const 
std::string& metadata_bytes,
 }
 
 VariantField encode_json(std::string_view json) {
-    JsonStringToVariantEncoder encoder({.max_json_key_length = 255,
-                                        .throw_on_invalid_json = true,
-                                        .check_duplicate_json_path = false});
+    JsonStringToVariantEncoder encoder({.max_json_key_length = 255, 
.throw_on_invalid_json = true});
     encoder.add_json({json.data(), json.size()});
     VariantBatchBuilder block = encoder.finish_batch();
     return VariantField::from_ref(block.value_at(0));
diff --git a/be/test/util/variant/variant_string_parse_test.cpp 
b/be/test/util/variant/variant_string_parse_test.cpp
index dd75979bb1b..2ebf419fecd 100644
--- a/be/test/util/variant/variant_string_parse_test.cpp
+++ b/be/test/util/variant/variant_string_parse_test.cpp
@@ -282,64 +282,16 @@ TEST(VariantJsonTest, 
EncoderCopiesRowsBeforeParserReuseAndProducesCanonicalValu
     EXPECT_TRUE(canonical_equals(block.value_at(0), reparsed.value_at(0)));
 }
 
-TEST(VariantJsonTest, DuplicateKeysKeepFirstCompleteSubtreeWhenEnabled) {
-    JsonToVariantOptions options;
-    options.check_duplicate_json_path = true;
-    VariantBatchBuilder block = encode_jsons(
-            {R"({"a":1,"a":[2]})", R"({"a":[1],"a":2})", 
R"({"a":{"b":1},"a":{"c":2}})"}, options);
-    ASSERT_EQ(block.num_rows(), 3);
-    EXPECT_EQ(print_json(block.value_at(0)), R"({"a":1})");
-    EXPECT_EQ(print_json(block.value_at(1)), R"({"a":[1]})");
-    EXPECT_EQ(print_json(block.value_at(2)), R"({"a":{"b":1}})");
-
-    // This is member-level first-wins semantics. It deliberately removes the 
old PathInData
-    // flatten/merge artifact; it is not evidence that the broader T0.2 
comparison is complete.
-    VariantBatchBuilder dotted = encode_jsons({R"({"a.b":1,"a":{"b":2}})"}, 
options);
-    EXPECT_EQ(print_json(dotted.value_at(0)), R"({"a":{"b":2},"a.b":1})");
-}
-
-TEST(VariantJsonTest, DuplicateKeysFailWithoutPerObjectHashWhenDisabled) {
-    JsonToVariantOptions options;
-    options.check_duplicate_json_path = false;
-    expect_exception_code(ErrorCode::INVALID_ARGUMENT,
-                          [&] { 
static_cast<void>(encode_jsons({R"({"a":1,"a":2})"}, options)); });
-}
-
-TEST(VariantJsonTest, 
RepeatedDuplicateSchemasStayStableAcrossSchemaAndScalarRows) {
-    JsonToVariantOptions options;
-    options.check_duplicate_json_path = true;
-    VariantBatchBuilder block =
-            encode_jsons({R"({"a":1,"a":2})", R"({"a":3,"a":4})", "null", 
R"({"a":5,"a":6})",
-                          R"({"b":7,"b":8})", R"({"b":9,"b":10})"},
-                         options);
-    ASSERT_EQ(block.num_rows(), 6);
-    EXPECT_EQ(print_json(block.value_at(0)), R"({"a":1})");
-    EXPECT_EQ(print_json(block.value_at(1)), R"({"a":3})");
-    EXPECT_TRUE(block.value_at(2).is_null());
-    EXPECT_EQ(print_json(block.value_at(3)), R"({"a":5})");
-    EXPECT_EQ(print_json(block.value_at(4)), R"({"b":7})");
-    EXPECT_EQ(print_json(block.value_at(5)), R"({"b":9})");
-    std::vector<VariantRef> rows;
-    rows.reserve(block.num_rows());
-    for (size_t index = 0; index < block.num_rows(); ++index) {
-        rows.push_back(block.value_at(index));
+TEST(VariantJsonTest, DuplicateKeysFail) {
+    for (const std::string_view json :
+         {R"({"a":1,"a":2})", R"({"a":1,"a":[2]})", 
R"({"a":{"b":1},"a":{"c":2}})"}) {
+        expect_exception_code(ErrorCode::INVALID_ARGUMENT,
+                              [&] { static_cast<void>(encode_jsons({json})); 
});
     }
-    validate_canonical(block.metadata_ref(), rows);
-}
-
-TEST(VariantJsonTest, IgnoredDuplicateSubtreeStillValidatesKeysAndDepth) {
-    JsonToVariantOptions options;
-    options.max_json_key_length = 255;
-    options.check_duplicate_json_path = true;
-    const std::string oversized_key(256, 'k');
-    const std::string oversized = R"({"a":1,"a":{")" + oversized_key + 
R"(":2}})";
-    expect_exception_code(ErrorCode::INVALID_ARGUMENT,
-                          [&] { static_cast<void>(encode_jsons({oversized}, 
options)); });
 
-    const std::string too_deep =
-            R"({"a":1,"a":)" + nested_array_json(VARIANT_MAX_NESTING_DEPTH) + 
"}";
-    expect_exception_code(ErrorCode::INVALID_ARGUMENT,
-                          [&] { static_cast<void>(encode_jsons({too_deep}, 
options)); });
+    // A dotted key and a nested key are different members of a parsed value.
+    VariantBatchBuilder dotted = encode_jsons({R"({"a.b":1,"a":{"b":2}})"});
+    EXPECT_EQ(print_json(dotted.value_at(0)), R"({"a":{"b":2},"a.b":1})");
 }
 
 TEST(VariantJsonTest, KeyLengthBoundaryIsMeasuredInUtf8Bytes) {
@@ -359,13 +311,15 @@ TEST(VariantJsonTest, 
EmptyAndInvalidInputFollowExplicitPolicy) {
     permissive.throw_on_invalid_json = false;
     VariantBatchBuilder block = encode_jsons({std::string_view {}, "{"}, 
permissive);
     ASSERT_EQ(block.num_rows(), 2);
-    EXPECT_EQ(print_json(block.value_at(0)), "{}");
+    EXPECT_EQ(print_json(block.value_at(0)), R"("")");
     EXPECT_EQ(print_json(block.value_at(1)), R"("{")");
 
-    JsonToVariantOptions strict;
-    strict.throw_on_invalid_json = true;
+    const JsonToVariantOptions strict;
+    EXPECT_TRUE(strict.throw_on_invalid_json);
     expect_exception_code(ErrorCode::INVALID_ARGUMENT,
                           [&] { static_cast<void>(encode_jsons({"{"}, 
strict)); });
+    expect_exception_code(ErrorCode::INVALID_ARGUMENT,
+                          [&] { 
static_cast<void>(encode_jsons({std::string_view {}}, strict)); });
 
     const std::string invalid_utf8(1, static_cast<char>(0xFF));
     expect_exception_code(ErrorCode::INVALID_ARGUMENT, [&] {
@@ -520,8 +474,7 @@ TEST(VariantJsonTest, 
CurrentConfigIsSnapshottedAndExplicitOptionsAreValidated)
     const JsonToVariantOptions options = 
JsonToVariantOptions::current_config();
     EXPECT_EQ(options.max_json_key_length,
               static_cast<uint32_t>(config::variant_max_json_key_length));
-    EXPECT_EQ(options.throw_on_invalid_json, 
config::variant_throw_exeception_on_invalid_json);
-    EXPECT_EQ(options.check_duplicate_json_path, 
config::variant_enable_duplicate_json_path_check);
+    EXPECT_TRUE(options.throw_on_invalid_json);
 
     JsonToVariantOptions invalid;
     invalid.max_json_key_length = 0;
diff --git 
a/regression-test/data/external_table_p0/paimon/write/test_paimon_write_variant_errors.out
 
b/regression-test/data/external_table_p0/paimon/write/test_paimon_write_variant_errors.out
index f1b82f09fba..34103c655ef 100644
--- 
a/regression-test/data/external_table_p0/paimon/write/test_paimon_write_variant_errors.out
+++ 
b/regression-test/data/external_table_p0/paimon/write/test_paimon_write_variant_errors.out
@@ -1,7 +1,7 @@
 -- This file is automatically generated. You should know what you did if you 
want to edit this
 -- !variant_after_errors --
 20     false   true    {"recovered":true}
-21     false   \N      not-json
+21     true    \N      \N
 22     false   \N      {"typed":"string"}
 23     false   \N      7
 24     false   \N      values-string
diff --git a/regression-test/data/variant_p0/v2/variant_parse_functions.out 
b/regression-test/data/variant_p0/v2/variant_parse_functions.out
index c99fe822150..7ee80984502 100644
--- a/regression-test/data/variant_p0/v2/variant_parse_functions.out
+++ b/regression-test/data/variant_p0/v2/variant_parse_functions.out
@@ -8,10 +8,7 @@
 3      false   false   false   1       1
 
 -- !strict_error_to_null --
-true   false
-
--- !permissive_invalid_json_is_string --
-{      false   {       false
+true   true    true
 
 -- !key_too_long_error_to_null --
 true
@@ -19,6 +16,3 @@ true
 -- !duplicate_key_error_to_null --
 true
 
--- !duplicate_key_first_wins --
-{"dup":1}      {"dup":1}
-
diff --git 
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_variant_errors.groovy
 
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_variant_errors.groovy
index f2876e2b85d..88df82ebe09 100644
--- 
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_variant_errors.groovy
+++ 
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_variant_errors.groovy
@@ -215,8 +215,7 @@ suite("test_paimon_write_variant_errors", 
"p0,external,paimon,nonConcurrent") {
                 row.collect { value -> value == null ? null : value.toString() 
}
             })
 
-            // Invalid JSON is preserved as a Variant string unless the global
-            // throw-on-invalid-JSON option is enabled.
+            // try_parse_to_variant returns NULL for text that is not a JSON 
document.
             order_qt_variant_after_errors """
                 SELECT id, payload IS NULL,
                        CAST(payload['recovered'] AS BOOLEAN),
diff --git a/regression-test/suites/variant_p0/column_name.groovy 
b/regression-test/suites/variant_p0/column_name.groovy
index 037edd8f10e..1c98d7d9a36 100644
--- a/regression-test/suites/variant_p0/column_name.groovy
+++ b/regression-test/suites/variant_p0/column_name.groovy
@@ -66,14 +66,18 @@ suite("regression_test_variant_column_name", "p0, 
nonConcurrent"){
     qt_sql "select cast(Tags[''] as text) from var_column_name order by 
cast(Tags[''] as string)"
 
     // name with `.`
-    // When parser-side duplicate path deduplication is disabled, dotted keys 
and nested paths
-    // collide during Variant materialization and should report duplicated 
entry.
-    setBeConfigTemporary([variant_enable_duplicate_json_path_check: false]) {
-        sql "truncate table var_column_name"
+    sql "truncate table var_column_name"
+    if (enableVariantV2) {
+        // A dotted key and a nested key collide when the value is stored and 
fail the write.
         test {
             sql """insert into var_column_name values (7, 
${variantV2Function}('{"a.b": "UPPER CASE", "a" : {"b" : 123}}'))"""
             exception "may contains duplicated entry"
         }
+    } else {
+        // The V1 parser drops the duplicated path, so the write succeeds. 
Reset the table so the
+        // rows below stay the same in both modes.
+        sql """insert into var_column_name values (7, 
${variantV2Function}('{"a.b": "UPPER CASE", "a" : {"b" : 123}}'))"""
+        sql "truncate table var_column_name"
     }
     for (int i = 0; i < 7; i++) {
         sql """insert into var_column_name select * from var_column_name"""
@@ -83,9 +87,14 @@ suite("regression_test_variant_column_name", "p0, 
nonConcurrent"){
     qt_sql_cnt_3 "select count(Tags['a']['b']) from var_column_name"
     qt_sql_cnt_4 "select count(Tags['a']['c']) from var_column_name"
 
-    test {
+    if (enableVariantV2) {
+        test {
+            sql """insert into var_column_name values (7, 
${variantV2Function}('{"": "UPPER CASE", "": "lower case"}'))"""
+            exception "Duplicate Variant object key"
+        }
+    } else {
+        // The V1 parser keeps the first of the duplicated keys instead of 
failing the write.
         sql """insert into var_column_name values (7, 
${variantV2Function}('{"": "UPPER CASE", "": "lower case"}'))"""
-        exception enableVariantV2 ? "Duplicate Variant object key" : "may 
contains duplicated entry"
     }
 
     // test key length larger than 255 bytes
diff --git a/regression-test/suites/variant_p0/duplicate_json_path.groovy 
b/regression-test/suites/variant_p0/duplicate_json_path.groovy
index 7fcfeac97f7..da219dba280 100644
--- a/regression-test/suites/variant_p0/duplicate_json_path.groovy
+++ b/regression-test/suites/variant_p0/duplicate_json_path.groovy
@@ -17,109 +17,104 @@
 
 suite("duplicate_json_path", "p0") {
     def variantV2Function = getFeConfig("enable_variant_v2").toBoolean() ? 
"parse_to_variant" : ""
-    def customBeConfig = [
-        variant_enable_duplicate_json_path_check: true
-    ]
-    setBeConfigTemporary(customBeConfig) {
-        sql "DROP TABLE IF EXISTS duplicate_json_path"
-        sql """
-            CREATE TABLE duplicate_json_path (
-                k int,
-                v variant
-            )
-            DUPLICATE KEY(k)
-            DISTRIBUTED BY HASH(k) BUCKETS 1
-            PROPERTIES (
-                "replication_num" = "1",
-                "group_commit_interval_ms" = "2000",
-                "disable_auto_compaction" = "true"
-            );
-        """
+    sql "DROP TABLE IF EXISTS duplicate_json_path"
+    sql """
+        CREATE TABLE duplicate_json_path (
+            k int,
+            v variant
+        )
+        DUPLICATE KEY(k)
+        DISTRIBUTED BY HASH(k) BUCKETS 1
+        PROPERTIES (
+            "replication_num" = "1",
+            "group_commit_interval_ms" = "2000",
+            "disable_auto_compaction" = "true"
+        );
+    """
 
-        sql """insert into duplicate_json_path values (1, 
${variantV2Function}('{"a":42,"a":{"b":42}}'))"""
-        sql """insert into duplicate_json_path values (2, 
${variantV2Function}('{"a" : 123, "a" : "123"}'))"""
-        sql """insert into duplicate_json_path values (3, 
${variantV2Function}('{"a.b":1,"a":{"b":2}}'))"""
-        sql """insert into duplicate_json_path values (4, 
${variantV2Function}('{"a":{"b":3},"a.b":4}'))"""
-        sql """insert into duplicate_json_path values (5, 
${variantV2Function}('{"a":{"b":5},"a":{"c":6}}'))"""
-        sql """insert into duplicate_json_path values (6, 
${variantV2Function}('{"a":[1],"a":2}'))"""
-        sql """insert into duplicate_json_path values (7, 
${variantV2Function}('{"a":2,"a":[1]}'))"""
+    sql """insert into duplicate_json_path values (1, 
${variantV2Function}('{"a":42,"a":{"b":42}}'))"""
+    sql """insert into duplicate_json_path values (2, 
${variantV2Function}('{"a" : 123, "a" : "123"}'))"""
+    sql """insert into duplicate_json_path values (3, 
${variantV2Function}('{"a.b":1,"a":{"b":2}}'))"""
+    sql """insert into duplicate_json_path values (4, 
${variantV2Function}('{"a":{"b":3},"a.b":4}'))"""
+    sql """insert into duplicate_json_path values (5, 
${variantV2Function}('{"a":{"b":5},"a":{"c":6}}'))"""
+    sql """insert into duplicate_json_path values (6, 
${variantV2Function}('{"a":[1],"a":2}'))"""
+    sql """insert into duplicate_json_path values (7, 
${variantV2Function}('{"a":2,"a":[1]}'))"""
 
-        streamLoad {
-            table "duplicate_json_path"
-            set 'read_json_by_line', 'true'
-            set 'format', 'json'
-            set 'group_commit', 'async_mode'
-            unset 'label'
-            file 'duplicate_json_path.json'
-            time 10000
+    streamLoad {
+        table "duplicate_json_path"
+        set 'read_json_by_line', 'true'
+        set 'format', 'json'
+        set 'group_commit', 'async_mode'
+        unset 'label'
+        file 'duplicate_json_path.json'
+        time 10000
 
-            check { result, exception, startTime, endTime ->
-                if (exception != null) {
-                    throw exception
-                }
-                def json = parseJson(result)
-                assertEquals("success", json.Status.toLowerCase())
-                assertEquals(7, json.NumberTotalRows)
-                assertEquals(7, json.NumberLoadedRows)
+        check { result, exception, startTime, endTime ->
+            if (exception != null) {
+                throw exception
             }
+            def json = parseJson(result)
+            assertEquals("success", json.Status.toLowerCase())
+            assertEquals(7, json.NumberTotalRows)
+            assertEquals(7, json.NumberLoadedRows)
         }
+    }
 
-        for (int i = 0; i < 30; i++) {
-            def count = sql "select count(*) from duplicate_json_path"
-            if (count[0][0] == 14) {
-                break
-            }
-            sleep(1000)
+    for (int i = 0; i < 30; i++) {
+        def count = sql "select count(*) from duplicate_json_path"
+        if (count[0][0] == 14) {
+            break
         }
-        def totalRows = sql "select count(*) from duplicate_json_path"
-        assertEquals(14, totalRows[0][0])
-
-        // When duplicate path check is enabled, duplicate Variant paths keep 
the first value.
-        def expectedResultV1 = [
-                [1, "{\"b\":42}", "42", null],
-                [2, "123", null, null],
-                [3, "{\"b\":1}", "1", null],
-                [4, "{\"b\":3}", "3", null],
-                [5, "{\"b\":5,\"c\":6}", "5", "6"],
-                [6, "[1]", null, null],
-                [7, "2", null, null],
-                [8, "{\"b\":42}", "42", null],
-                [9, "123", null, null],
-                [10, "{\"b\":8}", "8", null],
-                [11, "{\"b\":10}", "10", null],
-                [12, "{\"b\":11,\"c\":12}", "11", "12"],
-                [13, "[13]", null, null],
-                [14, "14", null, null]
-        ]
-        def expectedResultV2 = [
-                [1, "42", null, null],
-                [2, "123", null, null],
-                [3, "{\"b\":2}", "2", null],
-                [4, "{\"b\":3}", "3", null],
-                [5, "{\"b\":5}", "5", null],
-                [6, "[1]", null, null],
-                [7, "2", null, null],
-                [8, "42", null, null],
-                [9, "123", null, null],
-                [10, "{\"b\":9}", "9", null],
-                [11, "{\"b\":10}", "10", null],
-                [12, "{\"b\":11}", "11", null],
-                [13, "[13]", null, null],
-                [14, "14", null, null]
-        ]
-        def expectedResult = getFeConfig("enable_variant_v2").toBoolean()
-                ? expectedResultV2 : expectedResultV1
+        sleep(1000)
+    }
+    def totalRows = sql "select count(*) from duplicate_json_path"
+    assertEquals(14, totalRows[0][0])
 
-        def queryResult = {
-            sql """
-            select k, cast(v['a'] as string), cast(v['a']['b'] as string), 
cast(v['a']['c'] as string)
-            from duplicate_json_path
-            order by k
-            """
-        }
-        assertEquals(expectedResult, queryResult())
+    // When duplicate path check is enabled, duplicate Variant paths keep the 
first value.
+    def expectedResultV1 = [
+            [1, "{\"b\":42}", "42", null],
+            [2, "123", null, null],
+            [3, "{\"b\":1}", "1", null],
+            [4, "{\"b\":3}", "3", null],
+            [5, "{\"b\":5,\"c\":6}", "5", "6"],
+            [6, "[1]", null, null],
+            [7, "2", null, null],
+            [8, "{\"b\":42}", "42", null],
+            [9, "123", null, null],
+            [10, "{\"b\":8}", "8", null],
+            [11, "{\"b\":10}", "10", null],
+            [12, "{\"b\":11,\"c\":12}", "11", "12"],
+            [13, "[13]", null, null],
+            [14, "14", null, null]
+    ]
+    def expectedResultV2 = [
+            [1, "42", null, null],
+            [2, "123", null, null],
+            [3, "{\"b\":2}", "2", null],
+            [4, "{\"b\":3}", "3", null],
+            [5, "{\"b\":5}", "5", null],
+            [6, "[1]", null, null],
+            [7, "2", null, null],
+            [8, "42", null, null],
+            [9, "123", null, null],
+            [10, "{\"b\":9}", "9", null],
+            [11, "{\"b\":10}", "10", null],
+            [12, "{\"b\":11}", "11", null],
+            [13, "[13]", null, null],
+            [14, "14", null, null]
+    ]
+    def expectedResult = getFeConfig("enable_variant_v2").toBoolean()
+            ? expectedResultV2 : expectedResultV1
 
-        trigger_and_wait_compaction("duplicate_json_path", "full")
-        assertEquals(expectedResult, queryResult())
+    def queryResult = {
+        sql """
+        select k, cast(v['a'] as string), cast(v['a']['b'] as string), 
cast(v['a']['c'] as string)
+        from duplicate_json_path
+        order by k
+        """
     }
+    assertEquals(expectedResult, queryResult())
+
+    trigger_and_wait_compaction("duplicate_json_path", "full")
+    assertEquals(expectedResult, queryResult())
 }
diff --git 
a/regression-test/suites/variant_p0/test_variant_json_functions.groovy 
b/regression-test/suites/variant_p0/test_variant_json_functions.groovy
index 52e62690746..c8684d45090 100644
--- a/regression-test/suites/variant_p0/test_variant_json_functions.groovy
+++ b/regression-test/suites/variant_p0/test_variant_json_functions.groovy
@@ -25,6 +25,7 @@ suite("test_variant_json_functions", "p0,nonConcurrent") {
         DUPLICATE KEY(k) DISTRIBUTED BY HASH(k) BUCKETS 1
         PROPERTIES ("replication_num" = "1")
     """
+    // parse_to_variant only accepts JSON documents, so the Variant string row 
is a JSON string.
     sql """
         INSERT INTO test_variant_json_functions
         SELECT k, parse_to_variant(doc) FROM (
@@ -32,7 +33,7 @@ suite("test_variant_json_functions", "p0,nonConcurrent") {
             UNION ALL SELECT 2, '{"a":2,"s":"yz","b":{"c":[3]},"n":{"m":true}}'
             UNION ALL SELECT 3, '[1,"two",{"three":3}]'
             UNION ALL SELECT 4, '42'
-            UNION ALL SELECT 5, 'abc'
+            UNION ALL SELECT 5, '"abc"'
             UNION ALL SELECT 6, NULL) t
     """
 
diff --git a/regression-test/suites/variant_p0/v2/variant_compute_v2.groovy 
b/regression-test/suites/variant_p0/v2/variant_compute_v2.groovy
index 7eaf85c4d0c..3a288f35df7 100644
--- a/regression-test/suites/variant_p0/v2/variant_compute_v2.groovy
+++ b/regression-test/suites/variant_p0/v2/variant_compute_v2.groovy
@@ -290,23 +290,21 @@ suite("variant_compute_v2", "p0,nonConcurrent") {
         FROM numbers("number" = "1")
     """
 
-    setBeConfigTemporary([variant_throw_exeception_on_invalid_json: true]) {
-        order_qt_parse_error_to_null """
+    order_qt_parse_error_to_null """
+        SELECT number,
+               CAST(try_parse_to_variant(payload) AS STRING),
+               try_parse_to_variant(payload) IS NULL
+        FROM (
             SELECT number,
-                   CAST(try_parse_to_variant(payload) AS STRING),
-                   try_parse_to_variant(payload) IS NULL
-            FROM (
-                SELECT number,
-                       CASE number
-                           WHEN 0 THEN '{"ok":1}'
-                           WHEN 1 THEN 'not-json'
-                           ELSE NULL
-                       END AS payload
-                FROM numbers("number" = "3")
-            ) t
-            ORDER BY number
-        """
-    }
+                   CASE number
+                       WHEN 0 THEN '{"ok":1}'
+                       WHEN 1 THEN 'not-json'
+                       ELSE NULL
+                   END AS payload
+            FROM numbers("number" = "3")
+        ) t
+        ORDER BY number
+    """
 
     order_qt_direct_result """
         SELECT ${variantV2Function}(CONCAT('{"id":', number, '}'))
diff --git 
a/regression-test/suites/variant_p0/v2/variant_parse_functions.groovy 
b/regression-test/suites/variant_p0/v2/variant_parse_functions.groovy
index abea8b350f6..94688dd41d0 100644
--- a/regression-test/suites/variant_p0/v2/variant_parse_functions.groovy
+++ b/regression-test/suites/variant_p0/v2/variant_parse_functions.groovy
@@ -38,81 +38,60 @@ suite("variant_parse_functions", "p0,nonConcurrent") {
         FROM (${nullableInput}) t ORDER BY id
     """
 
-    setBeConfigTemporary([variant_throw_exeception_on_invalid_json: true]) {
-        test {
-            sql """
-                SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                    parse_to_variant('{')
-            """
-            exception "Parse json document failed at row 0, error:"
-        }
-        test {
-            sql """
-                SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                    json_parse('{')
-            """
-            exception "Parse json document failed at row 0, error:"
-        }
-        order_qt_strict_error_to_null """
+    // Text that is not a JSON document, including an empty string, is an 
error; the TRY form
+    // returns NULL instead.
+    test {
+        sql """
             SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                try_parse_to_variant('{') IS NULL,
-                try_parse_to_variant('') IS NULL
+                parse_to_variant('{')
         """
+        exception "Parse json document failed at row 0, error:"
     }
-
-    setBeConfigTemporary([variant_throw_exeception_on_invalid_json: false]) {
-        order_qt_permissive_invalid_json_is_string """
+    test {
+        sql """
             SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                CAST(parse_to_variant('{') AS STRING),
-                parse_to_variant('{') IS NULL,
-                CAST(try_parse_to_variant('{') AS STRING),
-                try_parse_to_variant('{') IS NULL
+                parse_to_variant('')
         """
+        exception "Parse json document failed at row 0, error:"
     }
-
-    setBeConfigTemporary([
-            variant_throw_exeception_on_invalid_json: true,
-            variant_max_json_key_length: 3
-    ]) {
-        test {
-            sql """
-                SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                    parse_to_variant('{"long":1}')
-            """
-            exception "Parse json document failed at row 0, error:"
-        }
-        order_qt_key_too_long_error_to_null """
+    test {
+        sql """
             SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                try_parse_to_variant('{"long":1}') IS NULL
+                json_parse('{')
         """
+        exception "Parse json document failed at row 0, error:"
     }
+    order_qt_strict_error_to_null """
+        SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
+            try_parse_to_variant('{') IS NULL,
+            try_parse_to_variant('') IS NULL,
+            try_parse_to_variant('not-json') IS NULL
+    """
 
-    setBeConfigTemporary([
-            variant_throw_exeception_on_invalid_json: true,
-            variant_enable_duplicate_json_path_check: false
-    ]) {
+    setBeConfigTemporary([variant_max_json_key_length: 3]) {
         test {
             sql """
                 SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                    parse_to_variant('{"dup":1,"dup":2}')
+                    parse_to_variant('{"long":1}')
             """
             exception "Parse json document failed at row 0, error:"
         }
-        order_qt_duplicate_key_error_to_null """
+        order_qt_key_too_long_error_to_null """
             SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                try_parse_to_variant('{"dup":1,"dup":2}') IS NULL
+                try_parse_to_variant('{"long":1}') IS NULL
         """
     }
 
-    setBeConfigTemporary([
-            variant_throw_exeception_on_invalid_json: true,
-            variant_enable_duplicate_json_path_check: true
-    ]) {
-        order_qt_duplicate_key_first_wins """
+    test {
+        sql """
             SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
-                CAST(parse_to_variant('{"dup":1,"dup":2}') AS STRING),
-                CAST(try_parse_to_variant('{"dup":1,"dup":2}') AS STRING)
+                parse_to_variant('{"dup":1,"dup":2}')
         """
+        exception "Parse json document failed at row 0, error:"
     }
+    order_qt_duplicate_key_error_to_null """
+        SELECT /*+SET_VAR(enable_fold_constant_by_be=false)*/
+            try_parse_to_variant('{"dup":1,"dup":2}') IS NULL
+    """
     }
 }


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

Reply via email to