summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <evgen@moonbone.local>2005-10-28 15:24:46 +0400
committerunknown <evgen@moonbone.local>2005-10-28 15:24:46 +0400
commita7ed6ce441bd2ecdc7e12d9113b695ed3c1da45f (patch)
tree5a24308e4f52d570dc3e75bf25970ca572505cf8
parent5e8515d9f2ccada3e19b109196fb5654e7c9db92 (diff)
downloadmariadb-git-a7ed6ce441bd2ecdc7e12d9113b695ed3c1da45f.tar.gz
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.
-rw-r--r--mysql-test/r/analyse.result26
-rw-r--r--mysql-test/t/analyse.test25
-rw-r--r--sql/sql_select.cc25
-rw-r--r--sql/sql_select.h1
4 files changed, 66 insertions, 11 deletions
diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result
index 0ebd4a3e409..f8737d8082b 100644
--- a/mysql-test/r/analyse.result
+++ b/mysql-test/r/analyse.result
@@ -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
test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL
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;
diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test
index e38e43381bc..dfca8f575a4 100644
--- a/mysql-test/t/analyse.test
+++ b/mysql-test/t/analyse.test
@@ -57,4 +57,29 @@ insert into t1 values (100000);
select * from t1 procedure analyse (1,1);
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
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index fe5428abf45..f057e30b6eb 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1044,18 +1044,21 @@ JOIN::save_join_tab()
void
JOIN::exec()
{
+ List<Item> *columns_list= &fields_list;
int tmp_error;
DBUG_ENTER("JOIN::exec");
error= 0;
if (procedure)
{
- if (procedure->change_columns(fields_list) ||
- result->prepare(fields_list, unit))
+ procedure_fields_list= fields_list;
+ if (procedure->change_columns(procedure_fields_list) ||
+ result->prepare(procedure_fields_list, unit))
{
thd->limit_found_rows= thd->examined_row_count= 0;
DBUG_VOID_RETURN;
}
+ columns_list= &procedure_fields_list;
}
else if (test(select_options & OPTION_BUFFER_RESULT) &&
result && result->prepare(fields_list, unit))
@@ -1072,7 +1075,7 @@ JOIN::exec()
(zero_result_cause?zero_result_cause:"No tables used"));
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
even if we don't have any tables for prepared statements or if
@@ -1082,9 +1085,9 @@ JOIN::exec()
(!conds || conds->val_int()) &&
(!having || having->val_int()))
{
- if (do_send_rows && (procedure ? (procedure->send_row(fields_list) ||
- procedure->end_of_records())
- : result->send_data(fields_list)))
+ if (do_send_rows &&
+ (procedure ? (procedure->send_row(procedure_fields_list) ||
+ procedure->end_of_records()) : result->send_data(fields_list)))
error= 1;
else
{
@@ -1108,7 +1111,7 @@ JOIN::exec()
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(),
select_options,
zero_result_cause,
@@ -5845,13 +5848,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
JOIN_TAB *join_tab;
int (*end_select)(JOIN *, struct st_join_table *,bool);
DBUG_ENTER("do_select");
-
+ List<Item> *columns_list= procedure ? &join->procedure_fields_list : fields;
join->procedure=procedure;
/*
Tell the client how many fields there are in a row
*/
if (!table)
- join->result->send_fields(*fields,1);
+ join->result->send_fields(*columns_list, 1);
else
{
VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
@@ -5913,7 +5916,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
error=(*end_select)(join,join_tab,1);
}
else if (join->send_row_on_empty_set())
- error= join->result->send_data(*join->fields);
+ error= join->result->send_data(*columns_list);
}
else
{
@@ -6612,7 +6615,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(0); // Didn't match having
error=0;
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)
error=join->result->send_data(*join->fields);
if (error)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c7440fe4c3a..fe9bb7d69d3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -204,6 +204,7 @@ class JOIN :public Sql_alloc
//Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
List<Item> &fields_list; // hold field list passed to mysql_select
+ List<Item> procedure_fields_list;
int error;
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select