From 3eca4bf22e0f7ce74f04d17cd332096af92e6dc2 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Thu, 26 May 2005 20:36:14 +0200 Subject: [PATCH 01/10] Fixed BUG#9937: Crash on call to stored procedure. This only showed up on two known platforms, both ia64 (one HP-UX and one Linux wich icc). For some reason, they only get half the stack size they are supposed to have, which makes deep SP recursion overrun the stack before check_stack_overrun() is triggered. Also made som minor fixes in the check_stack_overrun() definition, supporting variable margins. No test case added, but the reason for the bug report was a failed existing test case on these machines, which now works. --- sql/item_cmpfunc.cc | 2 +- sql/item_func.cc | 10 ++-------- sql/item_subselect.cc | 2 +- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 24 +++++++++++++++++++++--- sql/sp_head.cc | 6 ++---- sql/sql_parse.cc | 4 ++-- sql/table.cc | 2 +- 8 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 89897a9d74f..078fcb14ca3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2321,7 +2321,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) */ and_tables_cache= ~(table_map) 0; - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; // Fatal error flag is set! /* The following optimization reduces the depth of an AND-OR tree. diff --git a/sql/item_func.cc b/sql/item_func.cc index db2aa735b0e..68f1cc52cff 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -293,14 +293,11 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; -#ifndef EMBEDDED_LIBRARY // Avoid compiler warning - char buff[STACK_BUFF_ALLOC]; // Max argument in function -#endif used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -2567,12 +2564,9 @@ bool udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { -#ifndef EMBEDDED_LIBRARY // Avoid compiler warning - char buff[STACK_BUFF_ALLOC]; // Max argument in function -#endif DBUG_ENTER("Item_udf_func::fix_fields"); - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) DBUG_RETURN(TRUE); // Fatal error flag is set! udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0fbcf32a83c..55eb44c3c55 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -138,7 +138,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); - if (check_stack_overrun(thd, (gptr)&res)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; res= engine->prepare(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5d11a047a8f..71c41547fe7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1078,7 +1078,7 @@ extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; -extern ulong query_buff_size, thread_stack,thread_stack_min; +extern ulong query_buff_size, thread_stack; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; extern ulong rpl_recovery_rank, thread_cache_size; @@ -1430,7 +1430,7 @@ inline int hexchar_to_int(char c) #ifndef EMBEDDED_LIBRARY extern "C" void unireg_abort(int exit_code); void kill_delayed_threads(void); -bool check_stack_overrun(THD *thd,char *dummy); +bool check_stack_overrun(THD *thd, long margin); #else #define unireg_abort(exit_code) DBUG_RETURN(exit_code) inline void kill_delayed_threads(void) {} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8c5ce22f7a6..ef8a80a1d1c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -348,7 +348,7 @@ uint tc_heuristic_recover= 0; uint volatile thread_count, thread_running; ulong back_log, connect_timeout, concurrency; ulong server_id, thd_startup_options; -ulong table_cache_size, thread_stack, thread_stack_min, what_to_log; +ulong table_cache_size, thread_stack, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; @@ -2090,7 +2090,13 @@ static void start_signal_handler(void) (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR); +#if defined(__ia64__) || defined(__ia64) + /* Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here */ + pthread_attr_setstacksize(&thr_attr,thread_stack*2); +#else pthread_attr_setstacksize(&thr_attr,thread_stack); +#endif #endif (void) pthread_mutex_lock(&LOCK_thread_count); @@ -3011,23 +3017,35 @@ int main(int argc, char **argv) init_signals(); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); +#if defined(__ia64__) || defined(__ia64) + /* Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here */ + pthread_attr_setstacksize(&connection_attrib,thread_stack*2); +#else pthread_attr_setstacksize(&connection_attrib,thread_stack); +#endif #ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE { /* Retrieve used stack size; Needed for checking stack overflows */ size_t stack_size= 0; pthread_attr_getstacksize(&connection_attrib, &stack_size); +#if defined(__ia64__) || defined(__ia64) + stack_size/= 2; +#endif /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ if (stack_size && stack_size < thread_stack) { if (global_system_variables.log_warnings) sql_print_warning("Asked for %ld thread stack, but got %ld", - thread_stack, stack_size); + thread_stack, stack_size); +#if defined(__ia64__) || defined(__ia64) + thread_stack= stack_size*2; +#else thread_stack= stack_size; +#endif } } #endif - thread_stack_min=thread_stack - STACK_MIN_SIZE; (void) thr_setconcurrency(concurrency); // 10 by default diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 988345694b2..f9aeb1e1f20 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -564,13 +564,11 @@ sp_head::execute(THD *thd) Item_change_list old_change_list; String old_packet; - -#ifndef EMBEDDED_LIBRARY - if (check_stack_overrun(thd, olddb)) + /* Use some extra margin for possible SP recursion and functions */ + if (check_stack_overrun(thd, 4*STACK_MIN_SIZE)) { DBUG_RETURN(-1); } -#endif dbchanged= FALSE; if (m_db.length && diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7078c8e7181..298ecc06d20 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4985,11 +4985,11 @@ long max_stack_used; #endif #ifndef EMBEDDED_LIBRARY -bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) +bool check_stack_overrun(THD *thd, long margin) { long stack_used; if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= - (long) thread_stack_min) + thread_stack - margin) { sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack); my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0)); diff --git a/sql/table.cc b/sql/table.cc index db753b2ed1c..bc31a38f24a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1815,7 +1815,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - if (check_stack_overrun(thd, (char *)&res)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; for (tbl= ancestor; tbl; tbl= tbl->next_local) From fcb3b0326ed3c60019eef079576c06af7eeb5583 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Fri, 27 May 2005 14:48:33 +0200 Subject: [PATCH 02/10] Fixed BUG#9559: Functions: Numeric Operations using -ve value gives incorrect results. Actually a problem when converting decimal to int for user variables. --- mysql-test/r/sp.result | 11 +++++++++++ mysql-test/t/sp.test | 19 +++++++++++++++++++ sql/item_func.cc | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index c1164380f09..da54c100178 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3098,4 +3098,15 @@ call bug5963_2(1)| call bug5963_2(1)| drop procedure bug5963_2| drop table t3| +drop function if exists bug9559| +create function bug9559() +returns int +begin +set @y = -6/2; +return @y; +end| +select bug9559()| +bug9559() +-3 +drop function bug9559| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 80acaacfdb3..18389f4d80a 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3801,6 +3801,25 @@ call bug5963_2(1)| drop procedure bug5963_2| drop table t3| +# +# BUG#9559: Functions: Numeric Operations using -ve value gives incorrect +# results. +# +--disable_warnings +drop function if exists bug9559| +--enable_warnings +create function bug9559() + returns int +begin + set @y = -6/2; + return @y; +end| + +select bug9559()| + +drop function bug9559| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item_func.cc b/sql/item_func.cc index 68f1cc52cff..92371e1a082 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3597,7 +3597,7 @@ longlong user_var_entry::val_int(my_bool *null_value) case DECIMAL_RESULT: { longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result); + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result); return result; } case STRING_RESULT: From 4c49970e0f389983995a2f75fb72842bc598729e Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Fri, 27 May 2005 16:19:25 +0200 Subject: [PATCH 03/10] Fixed BUG#8409: Stored procedure crash if function contains FLUSH by simply disabling FLUSH for stored functions. (I can't really work.) --- mysql-test/r/sp-error.result | 8 ++++++++ mysql-test/t/sp-error.test | 15 +++++++++++++++ sql/sql_yacc.yy | 5 +++++ 3 files changed, 28 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 7c19f60471a..5eb651e2fca 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -646,4 +646,12 @@ drop procedure if exists bug10537| create procedure bug10537() load data local infile '/tmp/somefile' into table t1| ERROR 0A000: LOAD DATA is not allowed in stored procedures +drop function if exists bug8409| +create function bug8409() +returns int +begin +flush tables; +return 5; +end| +ERROR 0A000: FLUSH is not allowed in stored procedures drop table t1| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 67e9be5dd5d..78a6cdd49e1 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -905,6 +905,21 @@ create procedure bug10537() load data local infile '/tmp/somefile' into table t1| +# +# BUG#8409: Stored procedure crash if function contains FLUSH +# +--disable_warnings +drop function if exists bug8409| +--enable_warnings +--error ER_SP_BADSTATEMENT +create function bug8409() + returns int +begin + flush tables; + return 5; +end| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b9676c8124..feb9b9a6363 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6511,6 +6511,11 @@ flush: FLUSH_SYM opt_no_write_to_binlog { LEX *lex=Lex; + if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_FUNCTION) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "FLUSH"); + YYABORT; + } lex->sql_command= SQLCOM_FLUSH; lex->type=0; lex->no_write_to_binlog= $2; } From 10cc5a46df746dd3478c536c7e420d6b523c9897 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 30 May 2005 03:01:51 -0700 Subject: [PATCH 04/10] olap.result, olap.test: Added test cases for bug #7894. sql_select.cc: Fixed bug #7894: GROUP BY queries with ROLLUP returned wrong results for expressions containing group by columns. The fix ensured correct results by replacement of all occurrences of group by fields in non-aggregate expressions for corresponding ref objects and preventing creation of fields in temporary tables for expression containing group by fields. --- mysql-test/r/olap.result | 68 +++++++++++++++++++++++++++- mysql-test/t/olap.test | 30 +++++++++++++ sql/sql_select.cc | 95 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 187 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 013952403d7..ab84fa5739a 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -248,7 +248,7 @@ concat(':',product,':') sum(profit) avg(profit) :Computer: 6900 1380.0000 :Phone: 10 10.0000 :TV: 600 120.0000 -:TV: 7785 519.0000 +NULL 7785 519.0000 select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; ERROR 42000: This version of MySQL doesn't yet support 'CUBE' explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; @@ -438,3 +438,69 @@ a SUM(a) SUM(a)+1 CONCAT(SUM(a),'x') SUM(a)+SUM(a) SUM(a) 5 5 6 5x 10 5 NULL 8 9 8x 16 8 DROP TABLE t1; +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); +SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +a a+1 SUM(a) +1 2 1 +2 3 2 +NULL NULL 3 +SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP; +a+1 +2 +3 +NULL +SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +a+SUM(a) +2 +4 +NULL +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; +a b +2 3 +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL; +a b +NULL NULL +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL; +a b +NULL NULL +SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP; +IFNULL(a, 'TEST') +1 +2 +TEST +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP; +a b SUM(b) +1 4 4 +1 NULL 4 +2 1 2 +2 2 4 +2 NULL 6 +4 1 4 +4 NULL 4 +NULL NULL 14 +SELECT a,b,SUM(b), a+b as c FROM t2 +GROUP BY a,b WITH ROLLUP HAVING c IS NULL; +a b SUM(b) c +1 NULL 4 NULL +2 NULL 6 NULL +4 NULL 4 NULL +NULL NULL 14 NULL +SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 +GROUP BY a, b WITH ROLLUP; +IFNULL(a, 'TEST') COALESCE(b, 'TEST') +1 4 +1 TEST +2 1 +2 2 +2 TEST +4 1 +4 TEST +TEST TEST +DROP TABLE t1,t2; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 09ba537bf3b..b9387d15320 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -208,3 +208,33 @@ SELECT a, SUM(a), SUM(a)+1, CONCAT(SUM(a),'x'), SUM(a)+SUM(a), SUM(a) DROP TABLE t1; +# +# Tests for bug #7894: ROLLUP over expressions on group by attributes +# + +CREATE TABLE t1 (a int(11)); +INSERT INTO t1 VALUES (1),(2); + +SELECT a, a+1, SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP; +SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING a IS NULL; +SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b IS NULL; +SELECT IFNULL(a, 'TEST') FROM t1 GROUP BY a WITH ROLLUP; + +CREATE TABLE t2 (a int, b int); +INSERT INTO t2 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT a,b,SUM(b) FROM t2 GROUP BY a,b WITH ROLLUP; +SELECT a,b,SUM(b), a+b as c FROM t2 + GROUP BY a,b WITH ROLLUP HAVING c IS NULL; +SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 + GROUP BY a, b WITH ROLLUP; + +DROP TABLE t1,t2; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7b27879ae28..4f192b9228e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9164,6 +9164,79 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) ROLLUP handling ****************************************************************************/ +/* + Replace occurences of group by fields in an expression by ref items + + SYNOPSIS + change_group_ref() + thd reference to the context + expr expression to make replacement + group_list list of references to group by items + changed out: returns 1 if item contains a replaced field item + + DESCRIPTION + The function replaces occurrences of group by fields in expr + by ref objects for these fields unless they are under aggregate + functions. + + IMPLEMENTATION + The function recursively traverses the tree of the expr expression, + looks for occurrences of the group by fields that are not under + aggregate functions and replaces them for the corresponding ref items. + + NOTES + This substitution is needed GROUP BY queries with ROLLUP if + SELECT list contains expressions over group by attributes. + + EXAMPLES + SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP + SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP + + RETURN + 0 if ok + 1 on error +*/ + +static bool change_group_ref(THD *thd, Item *expr, ORDER *group_list, + bool *changed) +{ + if (expr->type() != Item::FUNC_ITEM) + return 0; + Item_func *func_item= (Item_func *) expr; + if (func_item->arg_count) + { + Item **arg,**arg_end; + for (arg= func_item->arguments(), + arg_end= func_item->arguments()+func_item->arg_count; + arg != arg_end; arg++) + { + Item *item= *arg; + if (item->type() == Item::FIELD_ITEM || item->type() == Item::REF_ITEM) + { + ORDER *group_tmp; + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (item->eq(*group_tmp->item,0)) + { + Item *new_item; + if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) + return 1; // fatal_error is set + thd->change_item_tree(arg, new_item); + *changed= TRUE; + } + } + } + else if (item->type() == Item::FUNC_ITEM) + { + if (change_group_ref(thd, item, group_list, changed)) + return 1; + } + } + } + return 0; +} + + /* Allocate memory needed for other rollup functions */ bool JOIN::rollup_init() @@ -9208,19 +9281,31 @@ bool JOIN::rollup_init() for (j=0 ; j < fields_list.elements ; j++) rollup.fields[i].push_back(rollup.null_items[i]); } - List_iterator_fast it(fields_list); + List_iterator_fast it(all_fields); Item *item; while ((item= it++)) { ORDER *group_tmp; for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) { - if (*group_tmp->item == item) + if (item->eq(*group_tmp->item,0)) item->maybe_null= 1; } + if (item->type() == Item::FUNC_ITEM) + { + bool changed= 0; + if (change_group_ref(thd, item, group_list, &changed)) + return 1; + /* + We have to prevent creation of a field in a temporary table for + an expression that contains GROUP BY attributes. + Marking the expression item as 'with_sum_func' will ensure this. + */ + if (changed) + item->with_sum_func= 1; + } } return 0; - } @@ -9318,14 +9403,14 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, *(*func)= (Item_sum*) item; (*func)++; } - else if (real_fields) + else { /* Check if this is something that is part of this group by */ ORDER *group_tmp; for (group_tmp= start_group, i= pos ; group_tmp ; group_tmp= group_tmp->next, i++) { - if (*group_tmp->item == item) + if (item->eq(*group_tmp->item,0)) { /* This is an element that is used by the GROUP BY and should be From e8a6fa42783a484a6bfef802feb987513d0ff0db Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 30 May 2005 05:25:12 -0700 Subject: [PATCH 05/10] sql_select.cc: Post-review modifications for the fix of bug #7894. --- sql/sql_select.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4f192b9228e..0362f097cba 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9197,17 +9197,14 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) 1 on error */ -static bool change_group_ref(THD *thd, Item *expr, ORDER *group_list, +static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, bool *changed) { - if (expr->type() != Item::FUNC_ITEM) - return 0; - Item_func *func_item= (Item_func *) expr; - if (func_item->arg_count) + if (expr->arg_count) { Item **arg,**arg_end; - for (arg= func_item->arguments(), - arg_end= func_item->arguments()+func_item->arg_count; + for (arg= expr->arguments(), + arg_end= expr->arguments()+expr->arg_count; arg != arg_end; arg++) { Item *item= *arg; @@ -9228,7 +9225,7 @@ static bool change_group_ref(THD *thd, Item *expr, ORDER *group_list, } else if (item->type() == Item::FUNC_ITEM) { - if (change_group_ref(thd, item, group_list, changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, changed)) return 1; } } @@ -9294,7 +9291,7 @@ bool JOIN::rollup_init() if (item->type() == Item::FUNC_ITEM) { bool changed= 0; - if (change_group_ref(thd, item, group_list, &changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, &changed)) return 1; /* We have to prevent creation of a field in a temporary table for From 063896a6e72a663375211c1479bd8b21f8ed2385 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Tue, 31 May 2005 12:06:15 +0200 Subject: [PATCH 06/10] Post-review fixes of BUG#9937: Crash on call to stored procedure. --- sql/item_cmpfunc.cc | 2 +- sql/item_func.cc | 10 ++++++++-- sql/item_subselect.cc | 2 +- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 12 ++++++++---- sql/sp_head.cc | 2 +- sql/sql_parse.cc | 9 ++++++++- sql/table.cc | 2 +- 8 files changed, 30 insertions(+), 13 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 378d3645caf..66f0bf9c395 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2321,7 +2321,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) */ and_tables_cache= ~(table_map) 0; - if (check_stack_overrun(thd, STACK_MIN_SIZE)) + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) return TRUE; // Fatal error flag is set! /* The following optimization reduces the depth of an AND-OR tree. diff --git a/sql/item_func.cc b/sql/item_func.cc index 13c9aa92d6e..47dffa679e9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -293,11 +293,14 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; +#ifndef EMBEDDED_LIBRARY // Avoid compiler warning + char buff[STACK_BUFF_ALLOC]; // Max argument in function +#endif used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -2564,9 +2567,12 @@ bool udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { +#ifndef EMBEDDED_LIBRARY // Avoid compiler warning + char buff[STACK_BUFF_ALLOC]; // Max argument in function +#endif DBUG_ENTER("Item_udf_func::fix_fields"); - if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) DBUG_RETURN(TRUE); // Fatal error flag is set! udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 328bc75757b..5c26f3c079c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -138,7 +138,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); - if (check_stack_overrun(thd, STACK_MIN_SIZE)) + if (check_stack_overrun(thd, STACK_MIN_SIZE, (gptr)&res)) return TRUE; res= engine->prepare(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index e9a325f1fa7..eb7fa68e8e8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1429,11 +1429,11 @@ inline int hexchar_to_int(char c) #ifndef EMBEDDED_LIBRARY extern "C" void unireg_abort(int exit_code); void kill_delayed_threads(void); -bool check_stack_overrun(THD *thd, long margin); +bool check_stack_overrun(THD *thd, long margin, char *dummy); #else #define unireg_abort(exit_code) DBUG_RETURN(exit_code) inline void kill_delayed_threads(void) {} -#define check_stack_overrun(A, B) 0 +#define check_stack_overrun(A, B, C) 0 #endif #endif /* MYSQL_CLIENT */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e3a74d378fa..5479a5466f0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2091,8 +2091,10 @@ static void start_signal_handler(void) if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR); #if defined(__ia64__) || defined(__ia64) - /* Peculiar things with ia64 platforms - it seems we only have half the - stack size in reality, so we have to double it here */ + /* + Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here + */ pthread_attr_setstacksize(&thr_attr,thread_stack*2); #else pthread_attr_setstacksize(&thr_attr,thread_stack); @@ -3018,8 +3020,10 @@ int main(int argc, char **argv) if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); #if defined(__ia64__) || defined(__ia64) - /* Peculiar things with ia64 platforms - it seems we only have half the - stack size in reality, so we have to double it here */ + /* + Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here + */ pthread_attr_setstacksize(&connection_attrib,thread_stack*2); #else pthread_attr_setstacksize(&connection_attrib,thread_stack); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9d055d55f54..fcca1b51d1c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -565,7 +565,7 @@ sp_head::execute(THD *thd) String old_packet; /* Use some extra margin for possible SP recursion and functions */ - if (check_stack_overrun(thd, 4*STACK_MIN_SIZE)) + if (check_stack_overrun(thd, 4*STACK_MIN_SIZE, olddb)) { DBUG_RETURN(-1); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7edd93f8d0d..e2746ffbdc8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4986,7 +4986,14 @@ long max_stack_used; #endif #ifndef EMBEDDED_LIBRARY -bool check_stack_overrun(THD *thd, long margin) +/* + Note: The 'buf' parameter is necessary, even if it is unused here. + - fix_fields functions has a "dummy" buffer large enough for the + corresponding exec. (Thus we only have to check in fix_fields.) + - Passing to check_stack_overrun() prevents the compiler from removing it. + */ +bool check_stack_overrun(THD *thd, long margin, + char *buf __attribute__((unused))) { long stack_used; if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= diff --git a/sql/table.cc b/sql/table.cc index bc31a38f24a..eb4dbe5a1f3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1815,7 +1815,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - if (check_stack_overrun(thd, STACK_MIN_SIZE)) + if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res)) return TRUE; for (tbl= ancestor; tbl; tbl= tbl->next_local) From 7eaf78de853ede1b3fb5e3cb0362a1b8f4a9b9f0 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Tue, 31 May 2005 13:12:23 +0200 Subject: [PATCH 07/10] Small bug fix in SP item reusal (debug mode only). --- sql/item.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index bf62aa1ddad..52046b8eefb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -301,10 +301,10 @@ void *Item::operator new(size_t size, Item *reuse, uint *rsize) { if (reuse && size <= reuse->rsize) { - reuse->cleanup(); - TRASH((void *)reuse, size); if (rsize) (*rsize)= reuse->rsize; + reuse->cleanup(); + TRASH((void *)reuse, size); return (void *)reuse; } if (rsize) From 13351aae48444e77961632ab5f3ab3c9aad63a3c Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Tue, 31 May 2005 04:49:52 -0700 Subject: [PATCH 08/10] olap.result: Post merge corrections. --- mysql-test/r/olap.result | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 78326511f00..f3324838ef7 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -249,11 +249,11 @@ select product, country_id , year, sum(profit) from t1 group by product, country product country_id year sum(profit) select concat(':',product,':'), sum(profit),avg(profit) from t1 group by product with rollup; concat(':',product,':') sum(profit) avg(profit) -:Calculator: 275 68.7500 -:Computer: 6900 1380.0000 -:Phone: 10 10.0000 -:TV: 600 120.0000 -:TV: 7785 519.0000 +:Calculator: 275 68.75000 +:Computer: 6900 1380.00000 +:Phone: 10 10.00000 +:TV: 600 120.00000 +NULL 7785 519.00000 select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; ERROR 42000: This version of MySQL doesn't yet support 'CUBE' explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube; @@ -503,7 +503,7 @@ a+1 NULL SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; a+SUM(a) -2 +3 4 NULL SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; From a7d28e20aaaf86a6f4007aa1c3586ac9777a2b45 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Tue, 31 May 2005 05:56:22 -0700 Subject: [PATCH 09/10] olap.result: Fixed bug #10982. item.cc: Fixed bug #10982. In the function Item_ref::val_decimal by mistake the method Item_ref::val_decimal was used instead of Item_ref::val_decimal_result. --- mysql-test/r/olap.result | 2 +- sql/item.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index f3324838ef7..5ba2bc80484 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -503,7 +503,7 @@ a+1 NULL SELECT a+SUM(a) FROM t1 GROUP BY a WITH ROLLUP; a+SUM(a) -3 +2 4 NULL SELECT a, a+1 as b FROM t1 GROUP BY a WITH ROLLUP HAVING b > 2; diff --git a/sql/item.cc b/sql/item.cc index bf62aa1ddad..ef358d084f9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4358,7 +4358,7 @@ bool Item_ref::get_date(TIME *ltime,uint fuzzydate) my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) { - my_decimal *val= (*ref)->val_decimal(decimal_value); + my_decimal *val= (*ref)->val_decimal_result(decimal_value); null_value= (*ref)->null_value; return val; } From 76073d7bf5878e77435406e3b24346a547ea1e14 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Tue, 31 May 2005 18:36:32 +0200 Subject: [PATCH 10/10] Fixed BUG#9529: Stored Procedures: No Warning on truncation of procedure name during creation. Although it returns an error, consistent with the behaviour for other objects. (Unclear why we would allow the creation of SPs with truncated names.) --- mysql-test/r/sp-error.result | 4 ++++ mysql-test/t/sp-error.test | 10 ++++++++++ sql/sp.cc | 9 +++++++++ sql/sp.h | 1 + sql/sql_parse.cc | 6 ++++++ 5 files changed, 30 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 5eb651e2fca..ccdb46f10d0 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -654,4 +654,8 @@ flush tables; return 5; end| ERROR 0A000: FLUSH is not allowed in stored procedures +create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890() +begin +end| +ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890' is too long drop table t1| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 78a6cdd49e1..a2a43110b54 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -920,6 +920,16 @@ begin end| +# +# BUG#9529: Stored Procedures: No Warning on truncation of procedure name +# during creation. +# +--error ER_TOO_LONG_IDENT +create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890() +begin +end| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp.cc b/sql/sp.cc index a5b1f062456..4f89d6ba6da 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -120,6 +120,10 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, 'db', 'name' and 'type' and the first key is the primary key over the same fields. */ + if (name->m_name.length > table->field[1]->field_length) + { + DBUG_RETURN(SP_KEY_NOT_FOUND); + } table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin); table->field[1]->store(name->m_name.str, name->m_name.length, &my_charset_bin); @@ -389,6 +393,11 @@ db_create_routine(THD *thd, int type, sp_head *sp) ret= SP_GET_FIELD_FAILED; goto done; } + if (sp->m_name.length > table->field[MYSQL_PROC_FIELD_NAME]->field_length) + { + ret= SP_BAD_IDENTIFIER; + goto done; + } table->field[MYSQL_PROC_FIELD_DB]-> store(sp->m_db.str, sp->m_db.length, system_charset_info); table->field[MYSQL_PROC_FIELD_NAME]-> diff --git a/sql/sp.h b/sql/sp.h index 00dd8416c1d..16d79026132 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -28,6 +28,7 @@ #define SP_PARSE_ERROR -6 #define SP_INTERNAL_ERROR -7 #define SP_NO_DB_ERROR -8 +#define SP_BAD_IDENTIFIER -9 /* Drop all routines in database 'db' */ int diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b36f88cf8c8..2191eba2f3e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4019,6 +4019,12 @@ unsent_create_error: delete lex->sphead; lex->sphead= 0; goto error; + case SP_BAD_IDENTIFIER: + my_error(ER_TOO_LONG_IDENT, MYF(0), name); + lex->unit.cleanup(); + delete lex->sphead; + lex->sphead= 0; + goto error; default: my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); lex->unit.cleanup();