From: Date: October 25 2005 11:42pm Subject: bk commit into 4.1 tree (evgen:1.2467) BUG#14138 List-Archive: http://lists.mysql.com/internals/31471 X-Bug: 14138 Message-Id: <20051025214251.E204522D89B@localhost.moonbone.local> Below is the list of changes that have just been committed into a local 4.1 repository of evgen. When evgen does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet 1.2467 05/10/26 01:42:47 evgen@stripped +4 -0 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 1.15 05/10/26 01:42:08 evgen@stripped +25 -0 Test case for bug #14138 ROLLUP and PROCEDURE ANALYSE() hang server mysql-test/r/analyse.result 1.18 05/10/26 01:41:49 evgen@stripped +26 -0 Test case for bug #14138 ROLLUP and PROCEDURE ANALYSE() hang server sql/sql_select.h 1.77 05/10/26 01:41:25 evgen@stripped +1 -0 Fix bug #14138 ROLLUP and PROCEDURE ANALYSE() hang server To JOIN Added separate fields_list for procedure. sql/sql_select.cc 1.441 05/10/26 01:36:30 evgen@stripped +14 -11 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. # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: evgen # Host: moonbone.local # Root: /work/14138-bug-4.1-mysql --- 1.440/sql/sql_select.cc 2005-10-13 18:25:25 +04:00 +++ 1.441/sql/sql_select.cc 2005-10-26 01:36:30 +04:00 @@ -1044,17 +1044,19 @@ JOIN::exec() { int tmp_error; + List *columns_list= &fields_list; DBUG_ENTER("JOIN::exec"); error= 0; if (procedure) { - if (procedure->change_columns(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; DBUG_VOID_RETURN; } + columns_list= &procedure_fields_list; } else if (test(select_options & OPTION_BUFFER_RESULT) && result && result->prepare(fields_list, unit)) @@ -1071,7 +1073,7 @@ (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 @@ -1081,9 +1083,9 @@ (!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 { @@ -1107,7 +1109,8 @@ 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, @@ -5844,13 +5847,13 @@ JOIN_TAB *join_tab; int (*end_select)(JOIN *, struct st_join_table *,bool); DBUG_ENTER("do_select"); - + List *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)); @@ -5912,7 +5915,7 @@ 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 { @@ -6611,7 +6614,7 @@ 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) --- 1.76/sql/sql_select.h 2005-06-23 17:13:38 +04:00 +++ 1.77/sql/sql_select.h 2005-10-26 01:41:25 +04:00 @@ -204,6 +204,7 @@ //Part, shared with list above, emulate following list List tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; List &fields_list; // hold field list passed to mysql_select + List procedure_fields_list; int error; ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select --- 1.17/mysql-test/r/analyse.result 2005-09-09 18:29:51 +04:00 +++ 1.18/mysql-test/r/analyse.result 2005-10-26 01:41:49 +04:00 @@ -108,3 +108,29 @@ 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; --- 1.14/mysql-test/t/analyse.test 2005-09-09 18:29:52 +04:00 +++ 1.15/mysql-test/t/analyse.test 2005-10-26 01:42:08 +04:00 @@ -57,4 +57,29 @@ 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