Bug#34773: query with explain extended and derived table / other table
crashes server When creating temporary table that contains aggregate functions a non-reversible source transformation was performed to redirect aggregate function arguments towards temporary table columns. This caused EXPLAIN EXTENDED to fail because it was trying to resolve references to the (freed) temporary table. Fixed by preserving the original aggregate function arguments and using them (instead of the transformed ones) for EXPLAIN EXTENDED. mysql-test/r/explain.result: Bug#34773: test case mysql-test/t/explain.test: Bug#34773: test case sql/item.cc: Bug#34773: use accessor functions instead of public members sql/item_sum.cc: Bug#34773: - Encapsulate the arguments into Item_sum and provide accessor and mutator methods - print the orginal arguments (if present) in EXPLAIN EXTENDED - preserve the original arguments list. sql/item_sum.h: Bug#34773: - Encapsulate the arguments into Item_sum and provide accessor and mutator methods - print the orginal arguments (if present) in EXPLAIN EXTENDED - preserve the original arguments list. sql/opt_range.cc: Bug#34773: use accessor functions instead of public members sql/opt_sum.cc: Bug#34773: use accessor functions instead of public members sql/sql_select.cc: Bug#34773: use accessor functions instead of public members
This commit is contained in:
parent
58f30a5886
commit
89d2b8efb9
@ -107,3 +107,51 @@ X X X X X X X X X
|
||||
X X X X X X X X X Range checked for each record (index map: 0xFFFFFFFFFF)
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a INT);
|
||||
CREATE TABLE t2(a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
INSERT INTO t2 VALUES (1),(2);
|
||||
EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer
|
||||
Warnings:
|
||||
Note 1003 select 1 AS `1` from (select count(distinct `test`.`t1`.`a`) AS `COUNT(DISTINCT t1.a)` from `test`.`t1` join `test`.`t2` group by `test`.`t1`.`a`) `s1`
|
||||
EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer
|
||||
Warnings:
|
||||
Note 1003 select 1 AS `1` from (select count(distinct `test`.`t1`.`a`) AS `COUNT(DISTINCT t1.a)` from `test`.`t1` join `test`.`t2` group by `test`.`t1`.`a`) `s1`
|
||||
prepare s1 from
|
||||
'EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1';
|
||||
execute s1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer
|
||||
Warnings:
|
||||
Note 1003 select 1 AS `1` from (select count(distinct `test`.`t1`.`a`) AS `COUNT(DISTINCT t1.a)` from `test`.`t1` join `test`.`t2` group by `test`.`t1`.`a`) `s1`
|
||||
prepare s1 from
|
||||
'EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1';
|
||||
execute s1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer
|
||||
Warnings:
|
||||
Note 1003 select 1 AS `1` from (select count(distinct `test`.`t1`.`a`) AS `COUNT(DISTINCT t1.a)` from `test`.`t1` join `test`.`t2` group by `test`.`t1`.`a`) `s1`
|
||||
execute s1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
|
||||
2 DERIVED t1 ALL NULL NULL NULL NULL 2 100.00 Using temporary; Using filesort
|
||||
2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00 Using join buffer
|
||||
Warnings:
|
||||
Note 1003 select 1 AS `1` from (select count(distinct `test`.`t1`.`a`) AS `COUNT(DISTINCT t1.a)` from `test`.`t1` join `test`.`t2` group by `test`.`t1`.`a`) `s1`
|
||||
DROP TABLE t1,t2;
|
||||
|
@ -94,4 +94,33 @@ EXPLAIN SELECT 1 FROM
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Bug #34773: query with explain extended and derived table / other table
|
||||
# crashes server
|
||||
#
|
||||
|
||||
CREATE TABLE t1(a INT);
|
||||
CREATE TABLE t2(a INT);
|
||||
INSERT INTO t1 VALUES (1),(2);
|
||||
INSERT INTO t2 VALUES (1),(2);
|
||||
|
||||
EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1;
|
||||
|
||||
EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1;
|
||||
|
||||
prepare s1 from
|
||||
'EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1';
|
||||
execute s1;
|
||||
|
||||
prepare s1 from
|
||||
'EXPLAIN EXTENDED SELECT 1
|
||||
FROM (SELECT COUNT(DISTINCT t1.a) FROM t1,t2 GROUP BY t1.a) AS s1';
|
||||
execute s1;
|
||||
execute s1;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
# End of 5.0 tests.
|
||||
|
@ -6919,7 +6919,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
|
||||
*/
|
||||
Item_sum *item_sum= (Item_sum *) item;
|
||||
if (item_sum->keep_field_type())
|
||||
return get_real_type(item_sum->args[0]);
|
||||
return get_real_type(item_sum->get_arg(0));
|
||||
break;
|
||||
}
|
||||
case FUNC_ITEM:
|
||||
@ -7182,7 +7182,7 @@ void Item_type_holder::get_full_info(Item *item)
|
||||
if (item->type() == Item::SUM_FUNC_ITEM &&
|
||||
(((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
|
||||
((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC))
|
||||
item = ((Item_sum*)item)->args[0];
|
||||
item = ((Item_sum*)item)->get_arg(0);
|
||||
/*
|
||||
We can have enum/set type after merging only if we have one enum|set
|
||||
field (or MIN|MAX(enum|set field)) and number of NULL fields
|
||||
|
@ -369,6 +369,10 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
|
||||
args[i++]= item;
|
||||
}
|
||||
}
|
||||
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
|
||||
{
|
||||
args= NULL;
|
||||
}
|
||||
mark_as_sum_func();
|
||||
list.empty(); // Fields are used
|
||||
}
|
||||
@ -379,18 +383,28 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
|
||||
*/
|
||||
|
||||
Item_sum::Item_sum(THD *thd, Item_sum *item):
|
||||
Item_result_field(thd, item), arg_count(item->arg_count),
|
||||
Item_result_field(thd, item),
|
||||
aggr_sel(item->aggr_sel),
|
||||
nest_level(item->nest_level), aggr_level(item->aggr_level),
|
||||
quick_group(item->quick_group), used_tables_cache(item->used_tables_cache),
|
||||
quick_group(item->quick_group),
|
||||
arg_count(item->arg_count), orig_args(NULL),
|
||||
used_tables_cache(item->used_tables_cache),
|
||||
forced_const(item->forced_const)
|
||||
{
|
||||
if (arg_count <= 2)
|
||||
{
|
||||
args=tmp_args;
|
||||
orig_args=tmp_orig_args;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
|
||||
return;
|
||||
if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
|
||||
return;
|
||||
}
|
||||
memcpy(args, item->args, sizeof(Item*)*arg_count);
|
||||
memcpy(orig_args, item->orig_args, sizeof(Item*)*arg_count);
|
||||
}
|
||||
|
||||
|
||||
@ -425,12 +439,13 @@ void Item_sum::make_field(Send_field *tmp_field)
|
||||
|
||||
void Item_sum::print(String *str, enum_query_type query_type)
|
||||
{
|
||||
Item **pargs= orig_args;
|
||||
str->append(func_name());
|
||||
for (uint i=0 ; i < arg_count ; i++)
|
||||
{
|
||||
if (i)
|
||||
str->append(',');
|
||||
args[i]->print(str, query_type);
|
||||
pargs[i]->print(str, query_type);
|
||||
}
|
||||
str->append(')');
|
||||
}
|
||||
@ -535,6 +550,13 @@ void Item_sum::update_used_tables ()
|
||||
}
|
||||
|
||||
|
||||
Item *Item_sum::set_arg(int i, THD *thd, Item *new_val)
|
||||
{
|
||||
thd->change_item_tree(args + i, new_val);
|
||||
return new_val;
|
||||
}
|
||||
|
||||
|
||||
String *
|
||||
Item_sum_num::val_str(String *str)
|
||||
{
|
||||
@ -586,6 +608,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
|
||||
if (check_sum_func(thd, ref))
|
||||
return TRUE;
|
||||
|
||||
memcpy (orig_args, args, sizeof (Item *) * arg_count);
|
||||
fixed= 1;
|
||||
return FALSE;
|
||||
}
|
||||
@ -673,6 +696,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
|
||||
if (check_sum_func(thd, ref))
|
||||
return TRUE;
|
||||
|
||||
orig_args[0]= args[0];
|
||||
fixed= 1;
|
||||
return FALSE;
|
||||
}
|
||||
@ -3141,6 +3165,12 @@ Item_func_group_concat(Name_resolution_context *context_arg,
|
||||
sizeof(ORDER*)*arg_count_order)))
|
||||
return;
|
||||
|
||||
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
|
||||
{
|
||||
args= NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
order= (ORDER**)(args + arg_count);
|
||||
|
||||
/* fill args items of show and sort */
|
||||
@ -3368,6 +3398,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
|
||||
if (check_sum_func(thd, ref))
|
||||
return TRUE;
|
||||
|
||||
memcpy (orig_args, args, sizeof (Item *) * arg_count);
|
||||
fixed= 1;
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -228,10 +228,8 @@ public:
|
||||
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
|
||||
};
|
||||
|
||||
Item **args, *tmp_args[2];
|
||||
Item **ref_by; /* pointer to a ref to the object used to register it */
|
||||
Item_sum *next; /* next in the circular chain of registered objects */
|
||||
uint arg_count;
|
||||
Item_sum *in_sum_func; /* embedding set function if any */
|
||||
st_select_lex * aggr_sel; /* select where the function is aggregated */
|
||||
int8 nest_level; /* number of the nesting level of the set function */
|
||||
@ -248,24 +246,32 @@ public:
|
||||
List<Item_field> outer_fields;
|
||||
|
||||
protected:
|
||||
uint arg_count;
|
||||
Item **args, *tmp_args[2];
|
||||
/*
|
||||
Copy of the arguments list to hold the original set of arguments.
|
||||
Used in EXPLAIN EXTENDED instead of the current argument list because
|
||||
the current argument list can be altered by usage of temporary tables.
|
||||
*/
|
||||
Item **orig_args, *tmp_orig_args[2];
|
||||
table_map used_tables_cache;
|
||||
bool forced_const;
|
||||
|
||||
public:
|
||||
|
||||
void mark_as_sum_func();
|
||||
Item_sum() :arg_count(0), quick_group(1), forced_const(FALSE)
|
||||
Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
|
||||
{
|
||||
mark_as_sum_func();
|
||||
}
|
||||
Item_sum(Item *a) :args(tmp_args), arg_count(1), quick_group(1),
|
||||
forced_const(FALSE)
|
||||
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
|
||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||
{
|
||||
args[0]=a;
|
||||
mark_as_sum_func();
|
||||
}
|
||||
Item_sum( Item *a, Item *b ) :args(tmp_args), arg_count(2), quick_group(1),
|
||||
forced_const(FALSE)
|
||||
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
|
||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||
{
|
||||
args[0]=a; args[1]=b;
|
||||
mark_as_sum_func();
|
||||
@ -374,6 +380,10 @@ public:
|
||||
bool register_sum_func(THD *thd, Item **ref);
|
||||
st_select_lex *depended_from()
|
||||
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
|
||||
|
||||
Item *get_arg(int i) { return args[i]; }
|
||||
Item *set_arg(int i, THD *thd, Item *new_val);
|
||||
uint get_arg_count() { return arg_count; }
|
||||
};
|
||||
|
||||
|
||||
@ -981,6 +991,7 @@ public:
|
||||
if (udf.fix_fields(thd, this, this->arg_count, this->args))
|
||||
return TRUE;
|
||||
|
||||
memcpy (orig_args, args, sizeof (Item *) * arg_count);
|
||||
return check_sum_func(thd, ref);
|
||||
}
|
||||
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
|
||||
|
@ -9157,7 +9157,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
/* The argument of MIN/MAX. */
|
||||
Item *expr= min_max_item->args[0]->real_item();
|
||||
Item *expr= min_max_item->get_arg(0)->real_item();
|
||||
if (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */
|
||||
{
|
||||
if (! min_max_arg_item)
|
||||
|
@ -199,7 +199,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
to the number of rows in the tables if this number is exact and
|
||||
there are no outer joins.
|
||||
*/
|
||||
if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null &&
|
||||
if (!conds && !((Item_sum_count*) item)->get_arg(0)->maybe_null &&
|
||||
!outer_tables && maybe_exact_count)
|
||||
{
|
||||
if (!is_exact_count)
|
||||
@ -225,7 +225,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
parts of the key is found in the COND, then we can use
|
||||
indexes to find the key.
|
||||
*/
|
||||
Item *expr=item_sum->args[0];
|
||||
Item *expr=item_sum->get_arg(0);
|
||||
if (expr->real_item()->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
uchar key_buff[MAX_KEY_LENGTH];
|
||||
@ -373,7 +373,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
parts of the key is found in the COND, then we can use
|
||||
indexes to find the key.
|
||||
*/
|
||||
Item *expr=item_sum->args[0];
|
||||
Item *expr=item_sum->get_arg(0);
|
||||
if (expr->real_item()->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
uchar key_buff[MAX_KEY_LENGTH];
|
||||
|
@ -9780,11 +9780,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
}
|
||||
if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
|
||||
{ /* Can't calc group yet */
|
||||
((Item_sum*) item)->result_field=0;
|
||||
for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++)
|
||||
Item_sum *sum_item= (Item_sum *) item;
|
||||
sum_item->result_field=0;
|
||||
for (i=0 ; i < sum_item->get_arg_count() ; i++)
|
||||
{
|
||||
Item **argp= ((Item_sum*) item)->args + i;
|
||||
Item *arg= *argp;
|
||||
Item *arg= sum_item->get_arg(i);
|
||||
if (!arg->const_item())
|
||||
{
|
||||
Field *new_field=
|
||||
@ -9812,7 +9812,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
string_total_length+= new_field->pack_length();
|
||||
}
|
||||
thd->mem_root= mem_root_save;
|
||||
thd->change_item_tree(argp, new Item_field(new_field));
|
||||
arg= sum_item->set_arg(i, thd, new Item_field(new_field));
|
||||
thd->mem_root= &table->mem_root;
|
||||
if (!(new_field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
@ -9821,7 +9821,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
new_field->maybe_null() is still false, it will be
|
||||
changed below. But we have to setup Item_field correctly
|
||||
*/
|
||||
(*argp)->maybe_null=1;
|
||||
arg->maybe_null=1;
|
||||
}
|
||||
new_field->field_index= fieldnr++;
|
||||
}
|
||||
@ -14491,9 +14491,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
|
||||
param->quick_group=0; // UDF SUM function
|
||||
param->sum_func_count++;
|
||||
|
||||
for (uint i=0 ; i < sum_item->arg_count ; i++)
|
||||
for (uint i=0 ; i < sum_item->get_arg_count() ; i++)
|
||||
{
|
||||
if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM)
|
||||
if (sum_item->get_arg(i)->real_item()->type() == Item::FIELD_ITEM)
|
||||
param->field_count++;
|
||||
else
|
||||
param->func_count++;
|
||||
|
Loading…
x
Reference in New Issue
Block a user