Commit a7ed6ce4 authored by unknown's avatar unknown

Fix bug #14138 ROLLUP and PROCEDURE ANALYSE() hang server

Procedure analyse() redefines select's fields_list. setup_copy_fields() assumes
that fields_list is a part of all_fields_list. Because select have only 
3 columns and analyse() redefines it to have 10 columns, int overrun in
setup_copy_fields() occurs and server goes to almost infinite loop.

Because fields_list used not only to send data ad fields types, it's wrong 
to allow procedure redefine it. This patch separates select's fileds_list 
and procedure's one. Now if procedure is present, copy of fields_list is 
created in procedure_fields_list and it is used for sending data and fields.


mysql-test/t/analyse.test:
  Test case for bug #14138  ROLLUP and PROCEDURE ANALYSE() hang server
mysql-test/r/analyse.result:
  Test case for bug #14138  ROLLUP and PROCEDURE ANALYSE() hang server
sql/sql_select.h:
  Fix bug #14138  ROLLUP and PROCEDURE ANALYSE() hang server
  To JOIN  Added separate fields_list for procedure.
sql/sql_select.cc:
  Fix bug #14138  ROLLUP and PROCEDURE ANALYSE() hang server
  SELECT's fields_list and procedure's fields_list made split. If procedure is defined
  then procedure's fields_list is used to send fields and data.
parent 5e8515d9
...@@ -108,3 +108,29 @@ select * from t1 procedure analyse (1,1); ...@@ -108,3 +108,29 @@ select * from t1 procedure analyse (1,1);
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL
drop table t1; drop table t1;
create table t1 (product varchar(32), country_id int not null, year int,
profit int);
insert into t1 values ( 'Computer', 2,2000, 1200),
( 'TV', 1, 1999, 150),
( 'Calculator', 1, 1999,50),
( 'Computer', 1, 1999,1500),
( 'Computer', 1, 2000,1500),
( 'TV', 1, 2000, 150),
( 'TV', 2, 2000, 100),
( 'TV', 2, 2000, 100),
( 'Calculator', 1, 2000,75),
( 'Calculator', 2, 2000,75),
( 'TV', 1, 1999, 100),
( 'Computer', 1, 1999,1200),
( 'Computer', 2, 2000,1500),
( 'Calculator', 2, 2000,75),
( 'Phone', 3, 2003,10)
;
create table t2 (country_id int primary key, country char(20) not null);
insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland');
select product, sum(profit),avg(profit) from t1 group by product with rollup procedure analyse();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.product Computer TV 2 8 0 0 4.2500 NULL ENUM('Computer','Phone','TV') NOT NULL
sum(profit) 10 6900 2 4 0 0 1946 2868 ENUM('10','275','600','6900') NOT NULL
avg(profit) 10.0000 1380.0000 7 9 0 0 394.6875 570.2003 ENUM('10.0000','68.7500','120.0000','1380.0000') NOT NULL
drop table t1,t2;
...@@ -57,4 +57,29 @@ insert into t1 values (100000); ...@@ -57,4 +57,29 @@ insert into t1 values (100000);
select * from t1 procedure analyse (1,1); select * from t1 procedure analyse (1,1);
drop table t1; drop table t1;
#
# Bug #14138 ROLLUP and PROCEDURE ANALYSE() hang server
#
create table t1 (product varchar(32), country_id int not null, year int,
profit int);
insert into t1 values ( 'Computer', 2,2000, 1200),
( 'TV', 1, 1999, 150),
( 'Calculator', 1, 1999,50),
( 'Computer', 1, 1999,1500),
( 'Computer', 1, 2000,1500),
( 'TV', 1, 2000, 150),
( 'TV', 2, 2000, 100),
( 'TV', 2, 2000, 100),
( 'Calculator', 1, 2000,75),
( 'Calculator', 2, 2000,75),
( 'TV', 1, 1999, 100),
( 'Computer', 1, 1999,1200),
( 'Computer', 2, 2000,1500),
( 'Calculator', 2, 2000,75),
( 'Phone', 3, 2003,10)
;
create table t2 (country_id int primary key, country char(20) not null);
insert into t2 values (1, 'USA'),(2,'India'), (3,'Finland');
select product, sum(profit),avg(profit) from t1 group by product with rollup procedure analyse();
drop table t1,t2;
# End of 4.1 tests # End of 4.1 tests
...@@ -1044,18 +1044,21 @@ JOIN::save_join_tab() ...@@ -1044,18 +1044,21 @@ JOIN::save_join_tab()
void void
JOIN::exec() JOIN::exec()
{ {
List<Item> *columns_list= &fields_list;
int tmp_error; int tmp_error;
DBUG_ENTER("JOIN::exec"); DBUG_ENTER("JOIN::exec");
error= 0; error= 0;
if (procedure) if (procedure)
{ {
if (procedure->change_columns(fields_list) || procedure_fields_list= fields_list;
result->prepare(fields_list, unit)) if (procedure->change_columns(procedure_fields_list) ||
result->prepare(procedure_fields_list, unit))
{ {
thd->limit_found_rows= thd->examined_row_count= 0; thd->limit_found_rows= thd->examined_row_count= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
columns_list= &procedure_fields_list;
} }
else if (test(select_options & OPTION_BUFFER_RESULT) && else if (test(select_options & OPTION_BUFFER_RESULT) &&
result && result->prepare(fields_list, unit)) result && result->prepare(fields_list, unit))
...@@ -1072,7 +1075,7 @@ JOIN::exec() ...@@ -1072,7 +1075,7 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used")); (zero_result_cause?zero_result_cause:"No tables used"));
else else
{ {
result->send_fields(fields_list,1); result->send_fields(*columns_list, 1);
/* /*
We have to test for 'conds' here as the WHERE may not be constant We have to test for 'conds' here as the WHERE may not be constant
even if we don't have any tables for prepared statements or if even if we don't have any tables for prepared statements or if
...@@ -1082,9 +1085,9 @@ JOIN::exec() ...@@ -1082,9 +1085,9 @@ JOIN::exec()
(!conds || conds->val_int()) && (!conds || conds->val_int()) &&
(!having || having->val_int())) (!having || having->val_int()))
{ {
if (do_send_rows && (procedure ? (procedure->send_row(fields_list) || if (do_send_rows &&
procedure->end_of_records()) (procedure ? (procedure->send_row(procedure_fields_list) ||
: result->send_data(fields_list))) procedure->end_of_records()) : result->send_data(fields_list)))
error= 1; error= 1;
else else
{ {
...@@ -1108,7 +1111,7 @@ JOIN::exec() ...@@ -1108,7 +1111,7 @@ JOIN::exec()
if (zero_result_cause) if (zero_result_cause)
{ {
(void) return_zero_rows(this, result, tables_list, fields_list, (void) return_zero_rows(this, result, tables_list, *columns_list,
send_row_on_empty_set(), send_row_on_empty_set(),
select_options, select_options,
zero_result_cause, zero_result_cause,
...@@ -5845,13 +5848,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -5845,13 +5848,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
JOIN_TAB *join_tab; JOIN_TAB *join_tab;
int (*end_select)(JOIN *, struct st_join_table *,bool); int (*end_select)(JOIN *, struct st_join_table *,bool);
DBUG_ENTER("do_select"); DBUG_ENTER("do_select");
List<Item> *columns_list= procedure ? &join->procedure_fields_list : fields;
join->procedure=procedure; join->procedure=procedure;
/* /*
Tell the client how many fields there are in a row Tell the client how many fields there are in a row
*/ */
if (!table) if (!table)
join->result->send_fields(*fields,1); join->result->send_fields(*columns_list, 1);
else else
{ {
VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
...@@ -5913,7 +5916,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -5913,7 +5916,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
error=(*end_select)(join,join_tab,1); error=(*end_select)(join,join_tab,1);
} }
else if (join->send_row_on_empty_set()) else if (join->send_row_on_empty_set())
error= join->result->send_data(*join->fields); error= join->result->send_data(*columns_list);
} }
else else
{ {
...@@ -6612,7 +6615,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -6612,7 +6615,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(0); // Didn't match having DBUG_RETURN(0); // Didn't match having
error=0; error=0;
if (join->procedure) if (join->procedure)
error=join->procedure->send_row(*join->fields); error=join->procedure->send_row(join->procedure_fields_list);
else if (join->do_send_rows) else if (join->do_send_rows)
error=join->result->send_data(*join->fields); error=join->result->send_data(*join->fields);
if (error) if (error)
......
...@@ -204,6 +204,7 @@ class JOIN :public Sql_alloc ...@@ -204,6 +204,7 @@ class JOIN :public Sql_alloc
//Part, shared with list above, emulate following list //Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
List<Item> &fields_list; // hold field list passed to mysql_select List<Item> &fields_list; // hold field list passed to mysql_select
List<Item> procedure_fields_list;
int error; int error;
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
......
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