createcentury opened a new pull request, #53327:
URL: https://github.com/apache/arrow/pull/53327

   ### Rationale for this change
   
   `DecimalConversions` in `scalar_cast_numeric.cc` follows a convention its 
own comments
   state: widening conversions "convert then scale", narrowing ones "scale then 
truncate".
   `SafeRescaleDecimal` relies on it, calling `ConvertInput` → `Rescale` → 
`FitsInPrecision`
   → `ConvertOutput`, so on every narrowing path the overflow check sees the 
full-width
   coefficient.
   
   `DecimalConversions<Decimal32, InDecimal>` is the only specialization that 
narrows in
   `ConvertInput`, and it is the single implementation behind every
   `Decimal{32,64,128,256} -> Decimal32` cast. Both `Rescale` and 
`FitsInPrecision`
   therefore ran against an already-truncated coefficient.
   
   This accounts for the three cases in #53288 exactly:
   
   - `5000000000 -> decimal32(9, 0)` returned `705032704`, which is `5000000000 
- 2^32`
   - `536870912000 -> decimal32(9, -3)` returned `0E+3`, because `536870912000` 
is exactly
     `125 * 2^32` and the low 32 bits are zero
   - `30000000.00 -> decimal32(9, 0)` was rejected, because the unscaled value 
`3000000000`
     wraps to `-1294967296`, which is no longer divisible by 100
   
   ### What changes are included in this PR?
   
   `DecimalConversions<Decimal32, InDecimal>` now has the same shape as
   `DecimalConversions<Decimal64, Decimal128>`: `ConvertInput` keeps 
`InDecimal` and
   `ConvertOutput` narrows. `low_bits()` is defined on `SmallBasicDecimal` as 
well as on
   `BasicDecimal128`/`BasicDecimal256`, so one generic specialization still 
covers all four
   source types.
   
   The unsafe paths (`allow_decimal_truncate=true`) change order too, which 
makes Decimal32
   consistent with the Decimal64 and Decimal128 outputs.
   
   ### Are these changes tested?
   
   Yes. `Cast.Decimal128ToDecimal32NarrowingChecksFullCoefficient` covers the 
three reported
   cases. I verified it fails on the unpatched kernel — the first case wrongly 
succeeds and
   the other two produce the wrong value or a spurious error — and passes with 
the change.
   The full `arrow-compute-scalar-cast-test` suite passes, 109 tests, including 
the existing
   Decimal tests that exercise both `allow_decimal_truncate` settings.
   
   ### Are there any user-facing changes?
   
   Yes. `cast` to `decimal32` now rejects values whose coefficient does not fit 
the target
   precision instead of silently wrapping, and accepts scale changes that are 
exact in the
   source width. Code that relied on the wrapped results will now see an error.
   
   **This PR contains a "Critical Fix".** A safe cast produced incorrect data 
without
   raising: `5000000000` became `705032704` with overflow checking enabled.
   
   ### Was AI used for this PR?
   
   In accordance to the [AI generation 
guidelines](https://arrow.apache.org/docs/dev/developers/overview.html#ai-generated-code),
 please disclose below whether and how AI was used in this PR.
   
   **PR code and description written by:**
   
   - [ ] Human
   - [x] AI
   
   **Reviewed before submission by:**
   
   - [x] Human
   - [ ] AI
   - [ ] Not reviewed
   


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

Reply via email to