Skip to content

fix: Correct two bugs when formatting decimal values - #10869

Merged
Jefffrey merged 1 commit into
apache:mainfrom
neilconway:neilc/fix-decimal-display
Aug 29, 2026
Merged

Jefffrey merged 1 commit into
apache:mainfrom
neilconway:neilc/fix-decimal-display

Conversation

@neilconway

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

By default, decimal values are not validated against their type's declared precision. Such out-of-precision values must therefore be handled correctly through arrow-rs. format_decimal_str attempted to do so by truncating the digit string to the declared precision, but that is not correct: for example, the value 12345 in a Decimal128(3, 1) context was formatted as 12.3, i.e., it silently produced incorrect values.

There are two principled ways to handle such values: format them in their full precision or return an error. Returning an error is impractical: (1) the formatting code doesn't have an easy way to surface such errors (2) this would be inconsistent with how out-of-precision decimals are handled throughout the rest of the Arrow ecosystem. Hence, this PR arranges to format out-of-precision values without truncation; the declared precision no longer affects formatting.

Along the way, fix a second bug: a 0 decimal value with a negative scale was zero-padded; for example, formatting with scale -2 resulted in the string "000". That is not a legal number in JSON, and is also just a surprising and likely unexpected behavior.

What changes are included in this PR?

  • Fix decimal formatting bugs as described above
  • Add/update tests

Are these changes tested?

Yes; new tests added.

Are there any user-facing changes?

Yes, but only in corner-cases. Both scenarios are rare to begin with, and the implemented behavior is unlikely to be what a user would desire.

format_decimal_str still takes a precision parameter that is now unused. I've kept that in the function signature to avoid breaking a public API.

`format_decimal_str` truncated the digit string to the declared
precision before placing the decimal point, so a value exceeding its
declared precision displayed as a different number (12345 at
Decimal128(3, 1), i.e. 1234.5, displayed as "12.3"), as a malformed
string (12345 at (3, 3) displayed as ".123"), or panicked on a
subtraction overflow when the scale exceeds the precision (constructible
via `with_data_type` and reachable from IPC/FFI input). Arrays are not
validated against their declared precision, and this path backs
`value_as_string`, casts to strings, pretty printing, and the CSV and
JSON writers.

Always format the full value; precision no longer affects formatting.
Also format a zero value at negative scale as "0" instead of
zero-padding it to "000", which is not a valid number and produced
invalid JSON writer output.

Closes apache#10866.
Closes apache#10865.
@github-actions github-actions Bot added arrow Changes to the arrow crate arrow-json arrow-json crate arrow-data arrow-cast labels Aug 26, 2026
@Jefffrey Jefffrey added the bug label Aug 27, 2026

@cakeni cakeni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Removing the precision-based truncation fixes both reported cases at the shared formatter, and the regression tests cover them.

@Jefffrey
Jefffrey merged commit 15449e9 into apache:main Aug 29, 2026
34 checks passed
@Jefffrey

Copy link
Copy Markdown
Contributor

thanks @neilconway & @cakeni

Rich-T-kid pushed a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 2, 2026
# Which issue does this PR close?

- Closes apache#10866.
- Closes apache#10865.

# Rationale for this change

By default, decimal values are not validated against their type's
declared precision. Such out-of-precision values must therefore be
handled correctly through arrow-rs. `format_decimal_str` attempted to do
so by truncating the digit string to the declared precision, but that is
not correct: for example, the value `12345` in a `Decimal128(3, 1)`
context was formatted as `12.3`, i.e., it silently produced incorrect
values.

There are two principled ways to handle such values: format them in
their full precision or return an error. Returning an error is
impractical: (1) the formatting code doesn't have an easy way to surface
such errors (2) this would be inconsistent with how out-of-precision
decimals are handled throughout the rest of the Arrow ecosystem. Hence,
this PR arranges to format out-of-precision values without truncation;
the declared precision no longer affects formatting.

Along the way, fix a second bug: a `0` decimal value with a negative
scale was zero-padded; for example, formatting with scale `-2` resulted
in the string "000". That is not a legal number in JSON, and is also
just a surprising and likely unexpected behavior.

# What changes are included in this PR?

* Fix decimal formatting bugs as described above
* Add/update tests

# Are these changes tested?

Yes; new tests added.

# Are there any user-facing changes?

Yes, but only in corner-cases. Both scenarios are rare to begin with,
and the implemented behavior is unlikely to be what a user would desire.

`format_decimal_str` still takes a `precision` parameter that is now
unused. I've kept that in the function signature to avoid breaking a
public API.
Rich-T-kid pushed a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 18, 2026
# Which issue does this PR close?

- Closes apache#10866.
- Closes apache#10865.

# Rationale for this change

By default, decimal values are not validated against their type's
declared precision. Such out-of-precision values must therefore be
handled correctly through arrow-rs. `format_decimal_str` attempted to do
so by truncating the digit string to the declared precision, but that is
not correct: for example, the value `12345` in a `Decimal128(3, 1)`
context was formatted as `12.3`, i.e., it silently produced incorrect
values.

There are two principled ways to handle such values: format them in
their full precision or return an error. Returning an error is
impractical: (1) the formatting code doesn't have an easy way to surface
such errors (2) this would be inconsistent with how out-of-precision
decimals are handled throughout the rest of the Arrow ecosystem. Hence,
this PR arranges to format out-of-precision values without truncation;
the declared precision no longer affects formatting.

Along the way, fix a second bug: a `0` decimal value with a negative
scale was zero-padded; for example, formatting with scale `-2` resulted
in the string "000". That is not a legal number in JSON, and is also
just a surprising and likely unexpected behavior.

# What changes are included in this PR?

* Fix decimal formatting bugs as described above
* Add/update tests

# Are these changes tested?

Yes; new tests added.

# Are there any user-facing changes?

Yes, but only in corner-cases. Both scenarios are rare to begin with,
and the implemented behavior is unlikely to be what a user would desire.

`format_decimal_str` still takes a `precision` parameter that is now
unused. I've kept that in the function signature to avoid breaking a
public API.
Rich-T-kid pushed a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 21, 2026
# Which issue does this PR close?

- Closes apache#10866.
- Closes apache#10865.

# Rationale for this change

By default, decimal values are not validated against their type's
declared precision. Such out-of-precision values must therefore be
handled correctly through arrow-rs. `format_decimal_str` attempted to do
so by truncating the digit string to the declared precision, but that is
not correct: for example, the value `12345` in a `Decimal128(3, 1)`
context was formatted as `12.3`, i.e., it silently produced incorrect
values.

There are two principled ways to handle such values: format them in
their full precision or return an error. Returning an error is
impractical: (1) the formatting code doesn't have an easy way to surface
such errors (2) this would be inconsistent with how out-of-precision
decimals are handled throughout the rest of the Arrow ecosystem. Hence,
this PR arranges to format out-of-precision values without truncation;
the declared precision no longer affects formatting.

Along the way, fix a second bug: a `0` decimal value with a negative
scale was zero-padded; for example, formatting with scale `-2` resulted
in the string "000". That is not a legal number in JSON, and is also
just a surprising and likely unexpected behavior.

# What changes are included in this PR?

* Fix decimal formatting bugs as described above
* Add/update tests

# Are these changes tested?

Yes; new tests added.

# Are there any user-facing changes?

Yes, but only in corner-cases. Both scenarios are rare to begin with,
and the implemented behavior is unlikely to be what a user would desire.

`format_decimal_str` still takes a `precision` parameter that is now
unused. I've kept that in the function signature to avoid breaking a
public API.
Rich-T-kid pushed a commit to Rich-T-kid/arrow-rs that referenced this pull request Sep 25, 2026
# Which issue does this PR close?

- Closes apache#10866.
- Closes apache#10865.

# Rationale for this change

By default, decimal values are not validated against their type's
declared precision. Such out-of-precision values must therefore be
handled correctly through arrow-rs. `format_decimal_str` attempted to do
so by truncating the digit string to the declared precision, but that is
not correct: for example, the value `12345` in a `Decimal128(3, 1)`
context was formatted as `12.3`, i.e., it silently produced incorrect
values.

There are two principled ways to handle such values: format them in
their full precision or return an error. Returning an error is
impractical: (1) the formatting code doesn't have an easy way to surface
such errors (2) this would be inconsistent with how out-of-precision
decimals are handled throughout the rest of the Arrow ecosystem. Hence,
this PR arranges to format out-of-precision values without truncation;
the declared precision no longer affects formatting.

Along the way, fix a second bug: a `0` decimal value with a negative
scale was zero-padded; for example, formatting with scale `-2` resulted
in the string "000". That is not a legal number in JSON, and is also
just a surprising and likely unexpected behavior.

# What changes are included in this PR?

* Fix decimal formatting bugs as described above
* Add/update tests

# Are these changes tested?

Yes; new tests added.

# Are there any user-facing changes?

Yes, but only in corner-cases. Both scenarios are rare to begin with,
and the implemented behavior is unlikely to be what a user would desire.

`format_decimal_str` still takes a `precision` parameter that is now
unused. I've kept that in the function signature to avoid breaking a
public API.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arrow Changes to the arrow crate arrow-cast arrow-data arrow-json arrow-json crate bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Displaying decimal values that exceed declared precision misbehaves Decimal zero with negative scale is formatted as "000"

3 participants