Description:
MySQL believes that taking a negative number modulo a positive number (via the % or MOD operator) can yield "negative zero" or "minus zero". This special constant does not compare equal to '-0', but it does compare equal to itself.
How to repeat:
SELECT -1 % 0.5;
+----------+
| -1 % 0.5 |
+----------+
| -0.0 |
+----------+
The right answer is "0.0", not "-0.0".
SELECT -0.0 = (-1 % 0.5);
+-------------------+
| -0.0 = (-1 % 0.5) |
+-------------------+
| 0 |
+-------------------+
The right answer is "1" (TRUE); -0.0 and 0.0 should be synonyms in this context.
Suggested fix:
do_div_mod() contains this code:
if (mod)
{
/* we're calculating N1 % N2.
The result will have
frac=max(frac1, frac2), as for subtraction
intg=intg2
*/
to->sign=from1->sign;
to->frac=max(from1->frac, from2->frac);
frac0=0;
}
It needs to follow that by the same logic that's duplicated already in a lot of other places (e.g. decimal_mul):
/* Now we have to check for -0.000 case */
if (to->sign)
{
dec1 *buf= to->buf;
dec1 *end= to->buf + intg0 + frac0;
DBUG_ASSERT(buf != end);
for (;;)
{
if (*buf)
break;
if (++buf == end)
{
/* We got decimal zero */
decimal_make_zero(to);
break;
}
}
}
Really, I strongly suggest pulling that logic out into a helper function named something like decimal_avoid_negative_zero() and calling that helper function from all the places where the code is currently duplicated.