eldenmoon opened a new pull request, #68016:
URL: https://github.com/apache/doris/pull/68016

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: #67675
   
   Problem Summary:
   Within a single Variant V2 segment, when a path's first value is a JSON bool 
and a plain number
   (TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE) arrives afterwards, the 
path silently turned the
   stored `true`/`false` into the integer `1`/`0`. Canonical Variant/JSON 
semantics require `true` to
   never compare or group equal to `1`, so this changed GROUP BY / equality / 
display results depending
   on row order.
   
   Root cause: `path_least_common_type()` 
(be/src/storage/segment/variant/v2/variant_path_builder.cpp)
   delegates ordinary scalar promotion to `get_least_supertype_jsonb()` /
   `get_numeric_type()` (be/src/core/data_type/get_least_supertype.cpp:62-63), 
which counts
   `TYPE_BOOLEAN` as an 8-bit unsigned integer so it can share width promotion 
with the real integer
   types. That rule is correct for `get_numeric_type()`'s other callers 
(data_type_array_serde.cpp,
   nested_group_streaming_write_plan.cpp, variant_util.cpp), but for a Variant 
path it merges BOOL and
   a number into one numeric column instead of falling back to JSONB. 
`promote()` then casts the
   already-written `true` value to that numeric type, turning it into `1` in 
storage. The opposite
   order (a number first, then a bool) already fell back to JSONB and kept the 
bool correct, because
   `append_integer()` throws when a BOOL value hits an already-numeric 
typed-path column and the
   `catch` block in `VariantPathBuilder::append()` promotes to JSONB; only 
bool-first was affected.
   
   Reproduction (before the fix):
   - BE UT (new): 
`VariantPathBuilderTest.BoolFirstThenNumericFallsBackToJsonbPreservingBooleanValue`
     failed with the path staying a numeric type and `to_string()` returning 
`"1"` instead of `"true"`.
     `BoolIntDoubleFalseSequenceKeepsBooleansAndNumbersDistinct` and
     `BoolAndIntArraysFallBackToJsonbElementPreservingBooleanValue` 
(ARRAY<BOOL> vs ARRAY<INT>) failed
     the same way.
   - SQL: a 1-bucket DUPLICATE table with one INSERT putting `{"k": true}` 
before `{"k": 1}` read back
     `var['k']` as `1` for the `true` row, and `GROUP BY var['k']` collapsed 
the two logically distinct
     rows into one group of size 2 instead of two groups of size 1.
   
   Fix: in `path_least_common_type()`, when exactly one side is `TYPE_BOOLEAN` 
and the other is one of
   TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE, return the JSONB type 
directly instead of
   delegating to the shared numeric-tower helper (mirroring the existing 
DECIMAL/ARRAY special-casing
   in the same function). The shared `get_least_supertype.cpp` numeric rule is 
left untouched since it
   has other callers that legitimately want BOOLEAN folded into the numeric 
tower; only this Variant
   path type-inference site is changed. Arrays are covered automatically 
because ARRAY-vs-ARRAY merges
   already recurse into this function for the element type.
   
   After the fix: all reproduction cases above pass; `var['k']` for the `true` 
row reads back `true`,
   and `GROUP BY` produces the correct distinct groups.
   
   ### Release note
   
   Fixed a Variant V2 storage bug where a JSON boolean value could be silently 
stored as the integer
   1/0 when, within one segment, the same path saw a bool value before a 
numeric value.
   
   ### Check List (For Author)
   
   - Test:
       - Unit Test: added 
`VariantPathBuilderTest.BoolFirstThenNumericFallsBackToJsonbPreservingBooleanValue`,
         `BoolIntDoubleFalseSequenceKeepsBooleansAndNumbersDistinct`, and
         `BoolAndIntArraysFallBackToJsonbElementPreservingBooleanValue` in
         be/test/storage/variant/variant_column_writer_reader_test.cpp. Ran the 
full test file
         (VariantPathBuilderTest, VariantShredderTest, 
VariantColumnWriterReaderTest,
         VariantWriterCompatibilityTest, 
VariantSpecializedWriterCompatibilityTest): before the fix the
         3 new cases failed as described above and all other cases passed; 
after the fix all 91 run
         cases passed (2 pre-existing skips: "NestedGroup write path is not 
available in this build",
         unrelated to this change).
       - Regression test: added 
regression-test/suites/variant_p0/test_variant_bool_numeric_widening.groovy,
         generated its .out with -genOut and verified every row by reasoning. 
Also ran the full
         variant_p0 directory (173 suites) on the fixed build: 9 unrelated 
pre-existing failures (1
         missing S3/OSS credential for an outfile export test; 8 
"debug_point/remove ... HTTP 500"
         failures confirmed via direct API probe to be caused by 
`config::enable_debug_points` being
         disabled in this cluster, affecting only inverted-index debug-point 
suites), none touching
         Variant type inference; the other 164 suites passed.
   - Behavior changed: Yes - a Variant path whose first value is a JSON bool 
now falls back to JSONB
     (instead of an incorrect numeric type) when a later value in the same path 
is a plain number, so
     `true`/`false` are preserved instead of becoming `1`/`0`.
   - Does this need documentation: No
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to