Commit ebb8c9fb authored by Alexander Barkov's avatar Alexander Barkov

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));
parent 2dc5d8bb
......@@ -472,3 +472,42 @@ select collation(cast("a" as char(10) ascii binary));
select collation(cast("a" as char(10) binary charset utf8));
select collation(cast("a" as char(10) binary ascii));
--echo #
--echo # MDEV-11030 Assertion `precision > 0' failed in decimal_bin_size
--echo #
SELECT * FROM (SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL)) sq;
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL, UNSIGNED), NULL);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT COALESCE(CONVERT(NULL, UNSIGNED), NULL);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT CASE WHEN TRUE THEN CONVERT(NULL, UNSIGNED) ELSE NULL END;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT IFNULL(CONVERT(NULL,SIGNED),CONVERT(NULL,UNSIGNED)) AS a;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT
-1,
CONVERT(NULL,SIGNED),
CONCAT(CONVERT(NULL,SIGNED)),
1,
CONVERT(NULL,UNSIGNED),
CONCAT(CONVERT(NULL,UNSIGNED));
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT
CONVERT('',SIGNED),
CONCAT(CONVERT('',SIGNED)),
CONVERT('',UNSIGNED),
CONCAT(CONVERT('',UNSIGNED));
SHOW CREATE TABLE t1;
DROP TABLE t1;
......@@ -533,7 +533,14 @@ uint Item::decimal_precision() const
unsigned_flag);
return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}
return MY_MIN(max_char_length(), DECIMAL_MAX_PRECISION);
uint res= max_char_length();
/*
Return at least one decimal digit, even if Item::max_char_length()
returned 0. This is important to avoid attempts to create fields of types
INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
*/
return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}
......
......@@ -626,8 +626,15 @@ class Item_func_signed :public Item_int_func
longlong val_int_from_str(int *error);
void fix_length_and_dec()
{
fix_char_length(MY_MIN(args[0]->max_char_length(),
MY_INT64_NUM_DECIMAL_DIGITS));
uint32 char_length= MY_MIN(args[0]->max_char_length(),
MY_INT64_NUM_DECIMAL_DIGITS);
/*
args[0]->max_char_length() can return 0.
Reserve max_length to fit at least one character for one digit,
plus one character for the sign (if signed).
*/
set_if_bigger(char_length, 1 + (unsigned_flag ? 0 : 1));
fix_char_length(char_length);
}
virtual void print(String *str, enum_query_type query_type);
uint decimal_precision() const { return args[0]->decimal_precision(); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment