Skip to content

Commit

Permalink
MDEV-17256 Decimal field multiplication bug.
Browse files Browse the repository at this point in the history
We should clear trailing zeroes in frac part. Otherwise
that tail is growing quickly and forces unnecessary truncating of
arguments.
  • Loading branch information
Alexey Botchkov committed Oct 30, 2018
1 parent 65cfc58 commit 5789831
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 16 deletions.
42 changes: 42 additions & 0 deletions mysql-test/r/type_newdecimal.result
Original file line number Diff line number Diff line change
Expand Up @@ -1997,3 +1997,45 @@ select 0.0000000001 mod 1;
select 0.01 mod 1;
0.01 mod 1
0.01
CREATE TABLE t1 (
`FLD1` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD2` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD3` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD4` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD5` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD6` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD7` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD8` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD9` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD10` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD11` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD12` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD13` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD14` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD15` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD16` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD17` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD18` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD19` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD20` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD21` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD22` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD23` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000
);
INSERT INTO t1 VALUES (001.0760,000.9500,001.0000,001.0000,001.0000,
001.0000,001.0000,001.0000,001.0000,001.0000,001.0000,000.5949,001.0194,
001.0000,001.0000,001.0000,001.0000,001.0000,001.0000,000.9220,001.1890,001.2130,327.2690);
select FLD1*FLD2*FLD3*FLD4*FLD5*FLD6*FLD7*FLD8*FLD9*FLD10*FLD11*FLD12*FLD13*FLD14*FLD15*FLD16*FLD17*FLD18*FLD19*FLD20*FLD21*FLD22*FLD23 as calc1 from t1;
calc1
269.775757576440530322187032000000
select FLD23*FLD2*FLD1*FLD4*FLD5*FLD11*FLD12*FLD13*FLD3*FLD15*FLD16*FLD17*FLD18*FLD19*FLD20*FLD21*FLD22*FLD14*FLD6*FLD7*FLD8*FLD9*FLD10 as calc2 from t1;
calc2
269.775757576440530322187032000000
DROP TABLE t1;
CREATE TABLE t1 AS SELECT 1.0 * 2.000;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`1.0 * 2.000` decimal(6,4) NOT NULL DEFAULT '0.0000'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
44 changes: 44 additions & 0 deletions mysql-test/t/type_newdecimal.test
Original file line number Diff line number Diff line change
Expand Up @@ -1581,3 +1581,47 @@ select 0.000000000000000000000000000000000000000000000000001 mod 1;
select 0.0000000001 mod 1;
select 0.01 mod 1;

#
# MDEV-17256 Decimal field multiplication bug
#

CREATE TABLE t1 (
`FLD1` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD2` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD3` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD4` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD5` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD6` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD7` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD8` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD9` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD10` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD11` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD12` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD13` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD14` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD15` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD16` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD17` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD18` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD19` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD20` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD21` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD22` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000,
`FLD23` decimal(7,4) unsigned zerofill NOT NULL DEFAULT 001.0000
);

INSERT INTO t1 VALUES (001.0760,000.9500,001.0000,001.0000,001.0000,
001.0000,001.0000,001.0000,001.0000,001.0000,001.0000,000.5949,001.0194,
001.0000,001.0000,001.0000,001.0000,001.0000,001.0000,000.9220,001.1890,001.2130,327.2690);

select FLD1*FLD2*FLD3*FLD4*FLD5*FLD6*FLD7*FLD8*FLD9*FLD10*FLD11*FLD12*FLD13*FLD14*FLD15*FLD16*FLD17*FLD18*FLD19*FLD20*FLD21*FLD22*FLD23 as calc1 from t1;
select FLD23*FLD2*FLD1*FLD4*FLD5*FLD11*FLD12*FLD13*FLD3*FLD15*FLD16*FLD17*FLD18*FLD19*FLD20*FLD21*FLD22*FLD14*FLD6*FLD7*FLD8*FLD9*FLD10 as calc2 from t1;

DROP TABLE t1;

CREATE TABLE t1 AS SELECT 1.0 * 2.000;
SHOW CREATE TABLE t1;
DROP TABLE t1;


35 changes: 19 additions & 16 deletions strings/decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2077,26 +2077,21 @@ int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
}
}

/* Now we have to check for -0.000 case */
if (to->sign)
/* Remove trailing zero words in frac part */
frac0= ROUND_UP(to->frac);

if (frac0 > 0 && to->buf[intg0 + frac0 - 1] == 0)
{
dec1 *buf= to->buf;
dec1 *end= to->buf + intg0 + frac0;
DBUG_ASSERT(buf != end);
for (;;)
do
{
if (*buf)
break;
if (++buf == end)
{
/* We got decimal zero */
decimal_make_zero(to);
break;
}
}
frac0--;
} while (frac0 > 0 && to->buf[intg0 + frac0 - 1] == 0);
to->frac= DIG_PER_DEC1 * frac0;
}

/* Remove heading zero words in intg part */
buf1= to->buf;
d_to_move= intg0 + ROUND_UP(to->frac);
d_to_move= intg0 + frac0;
while (!*buf1 && (to->intg > DIG_PER_DEC1))
{
buf1++;
Expand All @@ -2109,6 +2104,14 @@ int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to)
for (; d_to_move--; cur_d++, buf1++)
*cur_d= *buf1;
}

/* Now we have to check for -0.000 case */
if (to->sign && to->frac == 0 && to->buf[0] == 0)
{
DBUG_ASSERT(to->intg <= DIG_PER_DEC1);
/* We got decimal zero */
decimal_make_zero(to);
}
return error;
}

Expand Down

0 comments on commit 5789831

Please sign in to comment.