diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 3cd5028f85876..81d1637947c4b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -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; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index bb5a61d84eca4..adc8eb77198b5 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -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; + + diff --git a/strings/decimal.c b/strings/decimal.c index 3d90a58ea8a49..05546aa77a392 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -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++; @@ -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; }