mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Bug #40761: Assert on sum function on
IF(..., CAST(longtext AS UNSIGNED), signed_val) (was: LEFT JOIN on inline view crashes server) Select from a LONGTEXT column wrapped with an expression like "IF(..., CAST(longtext_column AS UNSIGNED), smth_signed)" failed an assertion or crashed the server. IFNULL function was affected too. LONGTEXT column item has a maximum length of 32^2-1 bytes, at the same time this is a maximum possible length of any MySQL item. CAST(longtext_column AS UNSIGNED) returns some unsigned numeric result of length 32^2-1, so the result of IF/IFNULL function of this number and some other signed number will have text length of (32^2-1)+1=32^2 (one byte for the minus sign) - there is integer overflow, and the length is equal to zero. That caused assert/crash. The bug has been fixed by the same solution as in the CASE function implementation. mysql-test/r/func_if.result: Added test case for bug #40761. mysql-test/t/func_if.test: Added test case for bug #40761. sql/item_cmpfunc.cc: Bug #40761: Assert on sum function on IF(..., CAST(longtext AS UNSIGNED), signed_val) 1. Item_func_case::agg_str_lengths method has been moved to the Item_func superclass. 2. Item_func_ifnull/Item_func_if::fix_length_and_dec methods have been updated to calculate max_length, decimals and unsigned flag like Item_func_case. sql/item_cmpfunc.h: Bug #40761: Assert on sum function on IF(..., CAST(longtext AS UNSIGNED), signed_val) Item_func_case::agg_str_lengths method has been moved to the Item_func superclass. sql/item_func.cc: Bug #40761: Assert on sum function on IF(..., CAST(longtext AS UNSIGNED), signed_val) Item_func_case::agg_str_lengths method has been moved to the Item_func superclass. sql/item_func.h: Bug #40761: Assert on sum function on IF(..., CAST(longtext AS UNSIGNED), signed_val) Item_func_case::agg_str_lengths method has been moved to the Item_func superclass.
This commit is contained in:
@ -176,4 +176,13 @@ IF((ROUND(t1.a,2)=1), 2,
|
|||||||
IF((ROUND(t1.a,2)=1), 2,
|
IF((ROUND(t1.a,2)=1), 2,
|
||||||
IF((R
|
IF((R
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
CREATE TABLE t1 (c LONGTEXT);
|
||||||
|
INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
|
||||||
|
SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
|
||||||
|
MAX(IF(1, CAST(c AS UNSIGNED), 0))
|
||||||
|
12345678901234567890
|
||||||
|
SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
|
||||||
|
MAX(IFNULL(CAST(c AS UNSIGNED), 0))
|
||||||
|
12345678901234567890
|
||||||
|
DROP TABLE t1;
|
||||||
End of 5.0 tests
|
End of 5.0 tests
|
||||||
|
@ -150,4 +150,17 @@ FROM t1;
|
|||||||
|
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #40761: Assert on sum func on IF(..., CAST(longtext AS UNSIGNED), signed)
|
||||||
|
# (was: LEFT JOIN on inline view crashes server)
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE TABLE t1 (c LONGTEXT);
|
||||||
|
INSERT INTO t1 VALUES(1), (2), (3), (4), ('12345678901234567890');
|
||||||
|
|
||||||
|
SELECT * FROM (SELECT MAX(IF(1, CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
|
||||||
|
SELECT * FROM (SELECT MAX(IFNULL(CAST(c AS UNSIGNED), 0)) FROM t1) AS te;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--echo End of 5.0 tests
|
||||||
|
@ -2069,21 +2069,23 @@ Item_func_ifnull::fix_length_and_dec()
|
|||||||
{
|
{
|
||||||
agg_result_type(&hybrid_type, args, 2);
|
agg_result_type(&hybrid_type, args, 2);
|
||||||
maybe_null=args[1]->maybe_null;
|
maybe_null=args[1]->maybe_null;
|
||||||
decimals= max(args[0]->decimals, args[1]->decimals);
|
|
||||||
unsigned_flag= args[0]->unsigned_flag && args[1]->unsigned_flag;
|
|
||||||
|
|
||||||
if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT)
|
if (hybrid_type == DECIMAL_RESULT || hybrid_type == INT_RESULT)
|
||||||
{
|
{
|
||||||
int len0= args[0]->max_length - args[0]->decimals
|
max_length= 0;
|
||||||
- (args[0]->unsigned_flag ? 0 : 1);
|
decimals= 0;
|
||||||
|
unsigned_flag= TRUE;
|
||||||
int len1= args[1]->max_length - args[1]->decimals
|
agg_num_lengths(args[0]);
|
||||||
- (args[1]->unsigned_flag ? 0 : 1);
|
agg_num_lengths(args[1]);
|
||||||
|
max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
|
||||||
max_length= max(len0, len1) + decimals + (unsigned_flag ? 0 : 1);
|
unsigned_flag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
max_length= max(args[0]->max_length, args[1]->max_length);
|
max_length= max(args[0]->max_length, args[1]->max_length);
|
||||||
|
decimals= max(args[0]->decimals, args[1]->decimals);
|
||||||
|
unsigned_flag=args[0]->unsigned_flag && args[1]->unsigned_flag;
|
||||||
|
}
|
||||||
|
|
||||||
switch (hybrid_type) {
|
switch (hybrid_type) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
@ -2238,8 +2240,6 @@ void
|
|||||||
Item_func_if::fix_length_and_dec()
|
Item_func_if::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
|
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
|
||||||
decimals= max(args[1]->decimals, args[2]->decimals);
|
|
||||||
unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
|
|
||||||
|
|
||||||
enum Item_result arg1_type=args[1]->result_type();
|
enum Item_result arg1_type=args[1]->result_type();
|
||||||
enum Item_result arg2_type=args[2]->result_type();
|
enum Item_result arg2_type=args[2]->result_type();
|
||||||
@ -2276,16 +2276,20 @@ Item_func_if::fix_length_and_dec()
|
|||||||
if ((cached_result_type == DECIMAL_RESULT )
|
if ((cached_result_type == DECIMAL_RESULT )
|
||||||
|| (cached_result_type == INT_RESULT))
|
|| (cached_result_type == INT_RESULT))
|
||||||
{
|
{
|
||||||
int len1= args[1]->max_length - args[1]->decimals
|
max_length= 0;
|
||||||
- (args[1]->unsigned_flag ? 0 : 1);
|
decimals= 0;
|
||||||
|
unsigned_flag= TRUE;
|
||||||
int len2= args[2]->max_length - args[2]->decimals
|
agg_num_lengths(args[1]);
|
||||||
- (args[2]->unsigned_flag ? 0 : 1);
|
agg_num_lengths(args[2]);
|
||||||
|
max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
|
||||||
max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
|
unsigned_flag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
max_length= max(args[1]->max_length, args[2]->max_length);
|
max_length= max(args[1]->max_length, args[2]->max_length);
|
||||||
|
decimals= max(args[1]->decimals, args[2]->decimals);
|
||||||
|
unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2633,16 +2637,6 @@ void Item_func_case::agg_str_lengths(Item* arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func_case::agg_num_lengths(Item *arg)
|
|
||||||
{
|
|
||||||
uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals,
|
|
||||||
arg->unsigned_flag) - arg->decimals;
|
|
||||||
set_if_bigger(max_length, len);
|
|
||||||
set_if_bigger(decimals, arg->decimals);
|
|
||||||
unsigned_flag= unsigned_flag && arg->unsigned_flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Item_func_case::fix_length_and_dec()
|
void Item_func_case::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
Item **agg;
|
Item **agg;
|
||||||
|
@ -759,7 +759,6 @@ public:
|
|||||||
Item *find_item(String *str);
|
Item *find_item(String *str);
|
||||||
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
|
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
|
||||||
void agg_str_lengths(Item *arg);
|
void agg_str_lengths(Item *arg);
|
||||||
void agg_num_lengths(Item *arg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -5668,3 +5668,13 @@ void Item_func_sp::update_used_tables()
|
|||||||
const_item_cache= FALSE;
|
const_item_cache= FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_func::agg_num_lengths(Item *arg)
|
||||||
|
{
|
||||||
|
uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals,
|
||||||
|
arg->unsigned_flag) - arg->decimals;
|
||||||
|
set_if_bigger(max_length, len);
|
||||||
|
set_if_bigger(decimals, arg->decimals);
|
||||||
|
unsigned_flag= unsigned_flag && arg->unsigned_flag;
|
||||||
|
}
|
||||||
|
@ -193,6 +193,8 @@ public:
|
|||||||
void * arg, traverse_order order);
|
void * arg, traverse_order order);
|
||||||
bool is_expensive_processor(byte *arg);
|
bool is_expensive_processor(byte *arg);
|
||||||
virtual bool is_expensive() { return 0; }
|
virtual bool is_expensive() { return 0; }
|
||||||
|
protected:
|
||||||
|
void agg_num_lengths(Item *arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user