ykisana opened a new pull request, #59443:
URL: https://github.com/apache/spark/pull/59443

   ### What changes were proposed in this pull request?
   
   `InternalRow.getWriterDefault` copies `UTF8String` values before storing 
them in the target row, but it matched strings with the stable identifier 
pattern `case StringType`. That pattern is an equality check against the 
`StringType` case object (UTF8_BINARY), and `StringType.equals` compares the 
collation id and constraint. A collated `StringType` (e.g. `UTF8_LCASE`, 
`UNICODE_CI`, `UTF8_LCASE_RTRIM`) and `CharType`/`VarcharType` therefore fell 
through to `case _ => input.update(ordinal, v)` and were stored **without** a 
copy.
   
   This PR changes the pattern to `case _: StringType`, so every string type 
takes the copying branch. This matches the codegen counterpart 
`CodeGenerator.setColumn`, which already uses `case _: StringType | ...` 
(changed in SPARK-46832 when collations were introduced); the interpreted path 
was missed at the time.
   
   ### Why are the changes needed?
   
   `InterpretedMutableProjection` (used by aggregation when 
`spark.sql.codegen.factoryMode=NO_CODEGEN`) and `InterpretedSafeProjection` 
write values through `InternalRow.getWriter`. Without the copy, the aggregation 
buffer keeps a pointer into the input row's memory, which is overwritten when 
the input `UnsafeRow` is reused. Interpreted MAX/MIN over collated strings then 
returns a wrong value or corrupted bytes:
   
   ```python
   df = spark.createDataFrame([("abcd",), ("xy",), ("ab",)], "s STRING COLLATE 
UTF8_LCASE")
   spark.conf.set("spark.sql.codegen.wholeStage", "false")
   spark.conf.set("spark.sql.codegen.factoryMode", "NO_CODEGEN")
   df.agg(F.max("s"), F.min("s")).collect()
   # expected: [Row(max(s)='xy', min(s)='ab')]
   # before:   [Row(max(s)='ab', min(s)='ab')]
   ```
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes, a bug fix. In interpreted (non-codegen) execution, aggregates such as 
MAX/MIN over collated strings (and CHAR/VARCHAR) could return wrong or 
corrupted values; they now return the correct result, matching codegen. Affects 
released versions (reported on 4.0.0, 4.1.1 and 4.2.0).
   
   ### How was this patch tested?
   
   Added `SPARK-60095: collated strings are copied into the buffer` to 
`MutableProjectionSuite`, run in both codegen and interpreted modes. It 
projects `UTF8_BINARY`, `UTF8_LCASE`, `UTF8_LCASE_RTRIM` and `UNICODE_CI` 
columns backed by one byte array, overwrites that array (simulating a reused 
input row), and checks the projected values are unchanged.
   
   - Without the fix: the `NO_CODEGEN` variant fails with `xbc did not equal 
abc`; the codegen variant passes.
   - With the fix: `build/sbt 'catalyst/testOnly *MutableProjectionSuite'` 
passes (22 tests).
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated by: Claude Opus 5.5
   Fix written by and all code manually reviewed by @ykisana.
   Tests, PR description, and comments by Claude.
   


-- 
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