Skip to content

Commit ebb8c9f

Browse files
author
Alexander Barkov
committed
MDEV-11030 Assertion `precision > 0' failed in decimal_bin_size
Fixing Item::decimal_precision() to return at least one digit. This fixes the problem reported in MDEV. Also, fixing Item_func_signed::fix_length_and_dec() to reserve space for at least one digit (plus one character for an optional sign). This is needed to have CONVERT(expr,SIGNED) and CONVERT(expr,UNSIGNED) create correct string fields when they appear in string context, e.g.: CREATE TABLE t1 AS SELECT CONCAT(CONVERT('',SIGNED));
1 parent 2dc5d8b commit ebb8c9f

File tree

4 files changed

+128
-4
lines changed

4 files changed

+128
-4
lines changed

mysql-test/r/cast.result

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ show create table t1;
583583
Table Create Table
584584
t1 CREATE TABLE `t1` (
585585
`cast(1 as unsigned)` int(1) unsigned NOT NULL,
586-
`cast(1 as signed)` int(1) NOT NULL,
586+
`cast(1 as signed)` int(2) NOT NULL,
587587
`cast(1 as double(5,2))` double(5,2) DEFAULT NULL,
588588
`cast(1 as decimal(5,3))` decimal(5,3) NOT NULL,
589589
`cast("A" as binary)` varbinary(1) NOT NULL,
@@ -819,3 +819,74 @@ utf8_bin
819819
select collation(cast("a" as char(10) binary ascii));
820820
collation(cast("a" as char(10) binary ascii))
821821
latin1_bin
822+
#
823+
# MDEV-11030 Assertion `precision > 0' failed in decimal_bin_size
824+
#
825+
SELECT * FROM (SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL)) sq;
826+
IFNULL(CONVERT(NULL, UNSIGNED), NULL)
827+
NULL
828+
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL);
829+
SHOW CREATE TABLE t1;
830+
Table Create Table
831+
t1 CREATE TABLE `t1` (
832+
`IFNULL(CONVERT(NULL, UNSIGNED), NULL)` decimal(1,0) DEFAULT NULL
833+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
834+
DROP TABLE t1;
835+
CREATE TABLE t1 AS SELECT COALESCE(CONVERT(NULL, UNSIGNED), NULL);
836+
SHOW CREATE TABLE t1;
837+
Table Create Table
838+
t1 CREATE TABLE `t1` (
839+
`COALESCE(CONVERT(NULL, UNSIGNED), NULL)` decimal(1,0) DEFAULT NULL
840+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
841+
DROP TABLE t1;
842+
CREATE TABLE t1 AS SELECT CASE WHEN TRUE THEN CONVERT(NULL, UNSIGNED) ELSE NULL END;
843+
SHOW CREATE TABLE t1;
844+
Table Create Table
845+
t1 CREATE TABLE `t1` (
846+
`CASE WHEN TRUE THEN CONVERT(NULL, UNSIGNED) ELSE NULL END` decimal(1,0) DEFAULT NULL
847+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
848+
DROP TABLE t1;
849+
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL,SIGNED),CONVERT(NULL,UNSIGNED)) AS a;
850+
SHOW CREATE TABLE t1;
851+
Table Create Table
852+
t1 CREATE TABLE `t1` (
853+
`a` decimal(1,0) DEFAULT NULL
854+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
855+
DROP TABLE t1;
856+
CREATE TABLE t1 AS SELECT
857+
-1,
858+
CONVERT(NULL,SIGNED),
859+
CONCAT(CONVERT(NULL,SIGNED)),
860+
1,
861+
CONVERT(NULL,UNSIGNED),
862+
CONCAT(CONVERT(NULL,UNSIGNED));
863+
SHOW CREATE TABLE t1;
864+
Table Create Table
865+
t1 CREATE TABLE `t1` (
866+
`-1` int(2) NOT NULL,
867+
`CONVERT(NULL,SIGNED)` int(2) DEFAULT NULL,
868+
`CONCAT(CONVERT(NULL,SIGNED))` varchar(2) DEFAULT NULL,
869+
`1` int(1) NOT NULL,
870+
`CONVERT(NULL,UNSIGNED)` int(1) unsigned DEFAULT NULL,
871+
`CONCAT(CONVERT(NULL,UNSIGNED))` varchar(1) DEFAULT NULL
872+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
873+
DROP TABLE t1;
874+
CREATE TABLE t1 AS SELECT
875+
CONVERT('',SIGNED),
876+
CONCAT(CONVERT('',SIGNED)),
877+
CONVERT('',UNSIGNED),
878+
CONCAT(CONVERT('',UNSIGNED));
879+
Warnings:
880+
Warning 1292 Truncated incorrect INTEGER value: ''
881+
Warning 1292 Truncated incorrect INTEGER value: ''
882+
Warning 1292 Truncated incorrect INTEGER value: ''
883+
Warning 1292 Truncated incorrect INTEGER value: ''
884+
SHOW CREATE TABLE t1;
885+
Table Create Table
886+
t1 CREATE TABLE `t1` (
887+
`CONVERT('',SIGNED)` int(2) NOT NULL,
888+
`CONCAT(CONVERT('',SIGNED))` varchar(2) NOT NULL,
889+
`CONVERT('',UNSIGNED)` int(1) unsigned NOT NULL,
890+
`CONCAT(CONVERT('',UNSIGNED))` varchar(1) NOT NULL
891+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
892+
DROP TABLE t1;

mysql-test/t/cast.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,42 @@ select collation(cast("a" as char(10) ascii binary));
472472
select collation(cast("a" as char(10) binary charset utf8));
473473
select collation(cast("a" as char(10) binary ascii));
474474

475+
--echo #
476+
--echo # MDEV-11030 Assertion `precision > 0' failed in decimal_bin_size
477+
--echo #
478+
479+
SELECT * FROM (SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL)) sq;
480+
481+
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL);
482+
SHOW CREATE TABLE t1;
483+
DROP TABLE t1;
484+
485+
CREATE TABLE t1 AS SELECT COALESCE(CONVERT(NULL, UNSIGNED), NULL);
486+
SHOW CREATE TABLE t1;
487+
DROP TABLE t1;
488+
489+
CREATE TABLE t1 AS SELECT CASE WHEN TRUE THEN CONVERT(NULL, UNSIGNED) ELSE NULL END;
490+
SHOW CREATE TABLE t1;
491+
DROP TABLE t1;
492+
493+
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL,SIGNED),CONVERT(NULL,UNSIGNED)) AS a;
494+
SHOW CREATE TABLE t1;
495+
DROP TABLE t1;
496+
497+
CREATE TABLE t1 AS SELECT
498+
-1,
499+
CONVERT(NULL,SIGNED),
500+
CONCAT(CONVERT(NULL,SIGNED)),
501+
1,
502+
CONVERT(NULL,UNSIGNED),
503+
CONCAT(CONVERT(NULL,UNSIGNED));
504+
SHOW CREATE TABLE t1;
505+
DROP TABLE t1;
506+
507+
CREATE TABLE t1 AS SELECT
508+
CONVERT('',SIGNED),
509+
CONCAT(CONVERT('',SIGNED)),
510+
CONVERT('',UNSIGNED),
511+
CONCAT(CONVERT('',UNSIGNED));
512+
SHOW CREATE TABLE t1;
513+
DROP TABLE t1;

sql/item.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,14 @@ uint Item::decimal_precision() const
533533
unsigned_flag);
534534
return MY_MIN(prec, DECIMAL_MAX_PRECISION);
535535
}
536-
return MY_MIN(max_char_length(), DECIMAL_MAX_PRECISION);
536+
uint res= max_char_length();
537+
/*
538+
Return at least one decimal digit, even if Item::max_char_length()
539+
returned 0. This is important to avoid attempts to create fields of types
540+
INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
541+
CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
542+
*/
543+
return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
537544
}
538545

539546

sql/item_func.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,8 +626,15 @@ class Item_func_signed :public Item_int_func
626626
longlong val_int_from_str(int *error);
627627
void fix_length_and_dec()
628628
{
629-
fix_char_length(MY_MIN(args[0]->max_char_length(),
630-
MY_INT64_NUM_DECIMAL_DIGITS));
629+
uint32 char_length= MY_MIN(args[0]->max_char_length(),
630+
MY_INT64_NUM_DECIMAL_DIGITS);
631+
/*
632+
args[0]->max_char_length() can return 0.
633+
Reserve max_length to fit at least one character for one digit,
634+
plus one character for the sign (if signed).
635+
*/
636+
set_if_bigger(char_length, 1 + (unsigned_flag ? 0 : 1));
637+
fix_char_length(char_length);
631638
}
632639
virtual void print(String *str, enum_query_type query_type);
633640
uint decimal_precision() const { return args[0]->decimal_precision(); }

0 commit comments

Comments
 (0)