Skip to content
/ server Public

MDEV-30255: fix trailing zeros from DISTINCT on decimals#4695

Open
MooSayed1 wants to merge 1 commit intoMariaDB:10.11from
MooSayed1:MDEV-30255
Open

MDEV-30255: fix trailing zeros from DISTINCT on decimals#4695
MooSayed1 wants to merge 1 commit intoMariaDB:10.11from
MooSayed1:MDEV-30255

Conversation

@MooSayed1
Copy link

@MooSayed1 MooSayed1 commented Feb 25, 2026

The Jira issue number for this PR is: MDEV-30255

Description

In a non-DISTINCT UNION ALL, a decimal expression like (c1 DIV 1)*0.1
with c1=0 declares decimals=1 (one fractional digit) but was showing
"0" instead of "0.0".

-- Expected: "0.0"  -- Bug showed: "0"
SELECT (c1 DIV 1)*0.1 FROM t1 WHERE c1=0
UNION ALL SELECT '1';

The DISTINCT path already produced the correct result; only the plain
UNION ALL path was broken.

The root cause is in Item::save_decimal_in_field() in sql/item.cc.
Two arithmetic operations silently reduce a decimal's frac attribute:

  • decimal_mul() strips trailing fractional zeros — 0 * 0.1 produces frac=0.
  • decimal_div() calls decimal_make_zero() for zero dividends, setting
    frac=0 and leaving the fractional buffer uninitialised.

Field_longstr::store_decimal() formats the string using dec->frac, so
frac=0"0" instead of the expected "0.0".

The fix: if the value's frac is less than the expression's declared decimals,
call round_to(decimals, TRUNCATE) before storing. round_to() is used
instead of a bare frac= assignment because it also zeroes the newly exposed
fractional buffer words that decimal_make_zero() leaves uninitialised.

The extension is guarded to decimals < DECIMAL_MAX_SCALE. Some items (e.g.
Item_func_get_user_var) set decimals = DECIMAL_MAX_SCALE (38) as a sentinel
for "unknown scale" and must not be extended.

Release Notes

UNION ALL on decimal expressions no longer strips trailing fractional zeros.
For example, (c1 DIV 1)*0.1 with c1=0 now correctly returns "0.0" instead of "0".

How can this PR be tested?

./mtr main.decimal_trailing_zeros

Basing the PR against the correct MariaDB version

This is a bug fix. The earliest affected branch is 10.11, so this PR targets upstream/10.11.

PR quality check

  • I checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am ok with the reviewer making the changes themselves.

How can this PR be tested?

./mtr main.decimal_trailing_zeros

The test creates an InnoDB table, runs the same decimal expression with and without DISTINCT, and verifies the results are identical.

Basing the PR against the correct MariaDB version

This is a bug fix targeting the 10.11 maintenance branch.

PR quality check

  • I checked the CODING_STANDARDS.md file and my PR conforms to this where appropriate.
  • For any trivial modifications to the PR, I am ok with the reviewer making the changes themselves.

@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Feb 25, 2026
Copy link
Member

@gkodinov gkodinov left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution. This is a preliminary review.

Please make sure you keep the single commit, but please add a commit message to it that is conformant to CODING_STANDARDS.md.

The rest of the change looks good to me, except one optional suggestion.

UNION ALL
(SELECT '2');

DROP TABLE t1;
Copy link
Member

Choose a reason for hiding this comment

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

Optional: We customarily add a comment to say "End of xx tests" for each version.

@MooSayed1
Copy link
Author

MooSayed1 commented Feb 25, 2026

@gkodinov I thought I had followed the CODING_STANDARDS.md correctly, since the commit message length is within the allowed number of characters 47, and there’s an exception for the ticket number.
I’m asking mainly to understand what was wrong so I can learn for next time.
maybe i need to add body explanation to the commit? i'll do it for now and i'll wait for the review.
Thank you for your reviews.

Copy link
Member

@gkodinov gkodinov left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks! Stand by for the final review.

Copy link
Contributor

@abarkov abarkov left a comment

Choose a reason for hiding this comment

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

I checked how it works in different scenarios:

drop table if exists t;
create table t (c1 double);
insert into t values (0.1);

SELECT (c1 DIV 1)*0.1 FROM t;                                   -- Returns 0.0
SELECT CAST((c1 DIV 1)*0.1 AS CHAR) FROM t;                     -- Returns 0.0
(SELECT (c1 DIV 1)*0.1 FROM t) UNION ALL (SELECT '1');          -- Returns 0
(SELECT DISTINCT (c1 DIV 1)*0.1 FROM t) UNION ALL (SELECT '1'); -- Returns 0.0

You're fixing the fourth query to return '0' instead of '0.0'.
But the correct change would be the other way around: fix the third query to return '0.0' instead of 0.

Please change your patch accordingly. Thanks.

@MooSayed1 MooSayed1 force-pushed the MDEV-30255 branch 2 times, most recently from 6c7befa to ada3c61 Compare February 26, 2026 17:03
The expression (e.g. (c1 DIV 1)*0.1) has a declared precision of
decimals=1.  decimal_mul() strips trailing fractional zeros from the
computed value -- for example 0*0.1 produces frac=0 -- so storing the
value into a UNION VARCHAR column via Item::save_decimal_in_field()
was producing "0" instead of the expected "0.0".

The DISTINCT path was unaffected because it stores through
Field_new_decimal::save_in_field(), which reads the field's own
dec attribute and preserves the full precision.

Fix: in Item::save_decimal_in_field(), after computing the value,
restore frac to at least the item's declared decimals before
calling field->store_decimal().

mysql-test/main/decimal_trailing_zeros.test,result: update expected
results and comments to reflect the correct behaviour: both the plain
and the DISTINCT variants of the UNION must show the same number of
fractional digits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

3 participants