Commit 613a9e3d authored by Georgi Kodinov's avatar Georgi Kodinov

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
parent 22ba9893
...@@ -107,3 +107,51 @@ X X X X X X X X X ...@@ -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) X X X X X X X X X Range checked for each record (index map: 0xFFFFFFFFFF)
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t1; 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 ...@@ -94,4 +94,33 @@ EXPLAIN SELECT 1 FROM
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t1; 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. # End of 5.0 tests.
...@@ -6919,7 +6919,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) ...@@ -6919,7 +6919,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
*/ */
Item_sum *item_sum= (Item_sum *) item; Item_sum *item_sum= (Item_sum *) item;
if (item_sum->keep_field_type()) if (item_sum->keep_field_type())
return get_real_type(item_sum->args[0]); return get_real_type(item_sum->get_arg(0));
break; break;
} }
case FUNC_ITEM: case FUNC_ITEM:
...@@ -7182,7 +7182,7 @@ void Item_type_holder::get_full_info(Item *item) ...@@ -7182,7 +7182,7 @@ void Item_type_holder::get_full_info(Item *item)
if (item->type() == Item::SUM_FUNC_ITEM && if (item->type() == Item::SUM_FUNC_ITEM &&
(((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
((Item_sum*)item)->sum_func() == Item_sum::MIN_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 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 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), ...@@ -369,6 +369,10 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements),
args[i++]= item; args[i++]= item;
} }
} }
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
{
args= NULL;
}
mark_as_sum_func(); mark_as_sum_func();
list.empty(); // Fields are used list.empty(); // Fields are used
} }
...@@ -379,18 +383,28 @@ Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements), ...@@ -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_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), aggr_sel(item->aggr_sel),
nest_level(item->nest_level), aggr_level(item->aggr_level), 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) forced_const(item->forced_const)
{ {
if (arg_count <= 2) if (arg_count <= 2)
{
args=tmp_args; args=tmp_args;
orig_args=tmp_orig_args;
}
else else
{
if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count))) if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
return; return;
if (!(orig_args= (Item**) thd->alloc(sizeof(Item*)*arg_count)))
return;
}
memcpy(args, item->args, sizeof(Item*)*arg_count); 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) ...@@ -425,12 +439,13 @@ void Item_sum::make_field(Send_field *tmp_field)
void Item_sum::print(String *str, enum_query_type query_type) void Item_sum::print(String *str, enum_query_type query_type)
{ {
Item **pargs= orig_args;
str->append(func_name()); str->append(func_name());
for (uint i=0 ; i < arg_count ; i++) for (uint i=0 ; i < arg_count ; i++)
{ {
if (i) if (i)
str->append(','); str->append(',');
args[i]->print(str, query_type); pargs[i]->print(str, query_type);
} }
str->append(')'); str->append(')');
} }
...@@ -535,6 +550,13 @@ void Item_sum::update_used_tables () ...@@ -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 * String *
Item_sum_num::val_str(String *str) Item_sum_num::val_str(String *str)
{ {
...@@ -586,6 +608,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) ...@@ -586,6 +608,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref)) if (check_sum_func(thd, ref))
return TRUE; return TRUE;
memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1; fixed= 1;
return FALSE; return FALSE;
} }
...@@ -673,6 +696,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) ...@@ -673,6 +696,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref)) if (check_sum_func(thd, ref))
return TRUE; return TRUE;
orig_args[0]= args[0];
fixed= 1; fixed= 1;
return FALSE; return FALSE;
} }
...@@ -3141,6 +3165,12 @@ Item_func_group_concat(Name_resolution_context *context_arg, ...@@ -3141,6 +3165,12 @@ Item_func_group_concat(Name_resolution_context *context_arg,
sizeof(ORDER*)*arg_count_order))) sizeof(ORDER*)*arg_count_order)))
return; return;
if (!(orig_args= (Item **) sql_alloc(sizeof(Item *) * arg_count)))
{
args= NULL;
return;
}
order= (ORDER**)(args + arg_count); order= (ORDER**)(args + arg_count);
/* fill args items of show and sort */ /* fill args items of show and sort */
...@@ -3368,6 +3398,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) ...@@ -3368,6 +3398,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
if (check_sum_func(thd, ref)) if (check_sum_func(thd, ref))
return TRUE; return TRUE;
memcpy (orig_args, args, sizeof (Item *) * arg_count);
fixed= 1; fixed= 1;
return FALSE; return FALSE;
} }
......
...@@ -228,10 +228,8 @@ class Item_sum :public Item_result_field ...@@ -228,10 +228,8 @@ class Item_sum :public Item_result_field
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC 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 **ref_by; /* pointer to a ref to the object used to register it */
Item_sum *next; /* next in the circular chain of registered objects */ Item_sum *next; /* next in the circular chain of registered objects */
uint arg_count;
Item_sum *in_sum_func; /* embedding set function if any */ Item_sum *in_sum_func; /* embedding set function if any */
st_select_lex * aggr_sel; /* select where the function is aggregated */ st_select_lex * aggr_sel; /* select where the function is aggregated */
int8 nest_level; /* number of the nesting level of the set function */ int8 nest_level; /* number of the nesting level of the set function */
...@@ -248,24 +246,32 @@ class Item_sum :public Item_result_field ...@@ -248,24 +246,32 @@ class Item_sum :public Item_result_field
List<Item_field> outer_fields; List<Item_field> outer_fields;
protected: 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; table_map used_tables_cache;
bool forced_const; bool forced_const;
public: public:
void mark_as_sum_func(); 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(); mark_as_sum_func();
} }
Item_sum(Item *a) :args(tmp_args), arg_count(1), quick_group(1), Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
forced_const(FALSE) orig_args(tmp_orig_args), forced_const(FALSE)
{ {
args[0]=a; args[0]=a;
mark_as_sum_func(); mark_as_sum_func();
} }
Item_sum( Item *a, Item *b ) :args(tmp_args), arg_count(2), quick_group(1), Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
forced_const(FALSE) orig_args(tmp_orig_args), forced_const(FALSE)
{ {
args[0]=a; args[1]=b; args[0]=a; args[1]=b;
mark_as_sum_func(); mark_as_sum_func();
...@@ -374,6 +380,10 @@ class Item_sum :public Item_result_field ...@@ -374,6 +380,10 @@ class Item_sum :public Item_result_field
bool register_sum_func(THD *thd, Item **ref); bool register_sum_func(THD *thd, Item **ref);
st_select_lex *depended_from() st_select_lex *depended_from()
{ return (nest_level == aggr_level ? 0 : aggr_sel); } { 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 @@ class Item_udf_sum : public Item_sum ...@@ -981,6 +991,7 @@ class Item_udf_sum : public Item_sum
if (udf.fix_fields(thd, this, this->arg_count, this->args)) if (udf.fix_fields(thd, this, this->arg_count, this->args))
return TRUE; return TRUE;
memcpy (orig_args, args, sizeof (Item *) * arg_count);
return check_sum_func(thd, ref); return check_sum_func(thd, ref);
} }
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
......
...@@ -9157,7 +9157,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) ...@@ -9157,7 +9157,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
/* The argument of MIN/MAX. */ /* 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 (expr->type() == Item::FIELD_ITEM) /* Is it an attribute? */
{ {
if (! min_max_arg_item) if (! min_max_arg_item)
......
...@@ -199,7 +199,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -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 to the number of rows in the tables if this number is exact and
there are no outer joins. 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) !outer_tables && maybe_exact_count)
{ {
if (!is_exact_count) if (!is_exact_count)
...@@ -225,7 +225,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -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 parts of the key is found in the COND, then we can use
indexes to find the key. 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) if (expr->real_item()->type() == Item::FIELD_ITEM)
{ {
uchar key_buff[MAX_KEY_LENGTH]; uchar key_buff[MAX_KEY_LENGTH];
...@@ -373,7 +373,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -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 parts of the key is found in the COND, then we can use
indexes to find the key. 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) if (expr->real_item()->type() == Item::FIELD_ITEM)
{ {
uchar key_buff[MAX_KEY_LENGTH]; uchar key_buff[MAX_KEY_LENGTH];
......
...@@ -9780,11 +9780,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -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) if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
{ /* Can't calc group yet */ { /* Can't calc group yet */
((Item_sum*) item)->result_field=0; Item_sum *sum_item= (Item_sum *) item;
for (i=0 ; i < ((Item_sum*) item)->arg_count ; i++) sum_item->result_field=0;
for (i=0 ; i < sum_item->get_arg_count() ; i++)
{ {
Item **argp= ((Item_sum*) item)->args + i; Item *arg= sum_item->get_arg(i);
Item *arg= *argp;
if (!arg->const_item()) if (!arg->const_item())
{ {
Field *new_field= Field *new_field=
...@@ -9812,7 +9812,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -9812,7 +9812,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
string_total_length+= new_field->pack_length(); string_total_length+= new_field->pack_length();
} }
thd->mem_root= mem_root_save; 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; thd->mem_root= &table->mem_root;
if (!(new_field->flags & NOT_NULL_FLAG)) if (!(new_field->flags & NOT_NULL_FLAG))
{ {
...@@ -9821,7 +9821,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -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 new_field->maybe_null() is still false, it will be
changed below. But we have to setup Item_field correctly changed below. But we have to setup Item_field correctly
*/ */
(*argp)->maybe_null=1; arg->maybe_null=1;
} }
new_field->field_index= fieldnr++; new_field->field_index= fieldnr++;
} }
...@@ -14491,9 +14491,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, ...@@ -14491,9 +14491,9 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
param->quick_group=0; // UDF SUM function param->quick_group=0; // UDF SUM function
param->sum_func_count++; 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++; param->field_count++;
else else
param->func_count++; param->func_count++;
......
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