diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 9411edcdc00..5ba2bc80484 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -253,7 +253,7 @@ concat(':',product,':') sum(profit) avg(profit) :Computer: 6900 1380.00000 :Phone: 10 10.00000 :TV: 600 120.00000 -:TV: 7785 519.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; @@ -489,3 +489,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/r/sp-error.result b/mysql-test/r/sp-error.result index 7c19f60471a..ccdb46f10d0 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -646,4 +646,16 @@ 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 +create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890() +begin +end| +ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890' is too long drop table t1| 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/olap.test b/mysql-test/t/olap.test index 88f778be4d5..c75cad0b051 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -220,3 +220,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/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 67e9be5dd5d..a2a43110b54 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -905,6 +905,31 @@ 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#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/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.cc b/sql/item.cc index 75a864d8bb5..2b132fb1b7e 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) @@ -4363,7 +4363,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; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8761f8076ca..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, buff)) + 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 72a4dff74e5..47dffa679e9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -300,7 +300,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) 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, buff)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -2572,7 +2572,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, #endif DBUG_ENTER("Item_udf_func::fix_fields"); - if (check_stack_overrun(thd, buff)) + 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); @@ -3603,7 +3603,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: diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 43af7df44e6..4556f60a659 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, (gptr)&res)) return TRUE; res= engine->prepare(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index aacc635a4a7..1ba153b2489 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1080,7 +1080,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; @@ -1431,11 +1431,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,char *dummy); +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 07ccb07e986..7ef4ec779b1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -350,7 +350,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; @@ -2086,7 +2086,15 @@ 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); @@ -3014,23 +3022,37 @@ 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.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/sp_head.cc b/sql/sp_head.cc index 217bcc0b728..fcca1b51d1c 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, olddb)) { DBUG_RETURN(-1); } -#endif dbchanged= FALSE; if (m_db.length && diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d806960400b..77afbfe12c6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4023,6 +4023,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(); @@ -4990,11 +4996,18 @@ long max_stack_used; #endif #ifndef EMBEDDED_LIBRARY -bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) +/* + 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)) >= - (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/sql_select.cc b/sql/sql_select.cc index 9252af8fa61..2edd8388d9b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12810,6 +12810,76 @@ 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_func *expr, ORDER *group_list, + bool *changed) +{ + if (expr->arg_count) + { + Item **arg,**arg_end; + for (arg= expr->arguments(), + arg_end= expr->arguments()+expr->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_func *) item, group_list, changed)) + return 1; + } + } + } + return 0; +} + + /* Allocate memory needed for other rollup functions */ bool JOIN::rollup_init() @@ -12854,19 +12924,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_func *) 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; - } @@ -12962,14 +13044,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)) { Item_null_result *null_item; /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f946c9bce30..b933876f4f3 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; } diff --git a/sql/table.cc b/sql/table.cc index 7ee9a3f4fc1..24b8c024a87 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1818,7 +1818,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, (char *)&res)) return TRUE; for (tbl= ancestor; tbl; tbl= tbl->next_local)