diff --git a/configure.in b/configure.in index ae26a0c44df..58682063593 100644 --- a/configure.in +++ b/configure.in @@ -342,7 +342,7 @@ AC_SUBST(CXXFLAGS) AC_SUBST(LD) AC_SUBST(INSTALL_SCRIPT) -export CC CXX CFLAGS LD LDFLAGS AR +export CC CXX CFLAGS LD LDFLAGS AR ARFLAGS if test "$GCC" = "yes" then diff --git a/innobase/configure.in b/innobase/configure.in index baf11272ab9..c56bd8274c4 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -117,6 +117,13 @@ case "$target" in CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; esac +# must go in pair with AR as set by MYSQL_CHECK_AR +if test -z "$ARFLAGS" +then + ARFLAGS="cru" +fi +AC_SUBST(ARFLAGS) + AC_OUTPUT(Makefile os/Makefile ut/Makefile btr/Makefile dnl buf/Makefile data/Makefile dnl dict/Makefile dyn/Makefile dnl diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6e2fb50d988..2051afc7745 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -303,7 +303,7 @@ sub mysqld_arguments ($$$$$); sub stop_masters_slaves (); sub stop_masters (); sub stop_slaves (); -sub run_mysqltest ($$); +sub run_mysqltest ($); sub usage ($); ###################################################################### @@ -1342,10 +1342,11 @@ sub run_testcase ($) { if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) { - if ( $tinfo->{'master_restart'} or $master->[0]->{'uses_special_flags'} ) + if ( $tinfo->{'master_restart'} or + $master->[0]->{'running_master_is_special'} ) { stop_masters(); - $master->[0]->{'uses_special_flags'}= 0; # Forget about why we stopped + $master->[0]->{'running_master_is_special'}= 0; # Forget why we stopped } # ---------------------------------------------------------------------- @@ -1423,9 +1424,9 @@ sub run_testcase ($) { } } - if ( @{$tinfo->{'master_opt'}} ) + if ( $tinfo->{'master_restart'} ) { - $master->[0]->{'uses_special_flags'}= 1; + $master->[0]->{'running_master_is_special'}= 1; } } @@ -1472,7 +1473,7 @@ sub run_testcase ($) { } unlink($path_timefile); - my $res= run_mysqltest($tinfo, $tinfo->{'master_opt'}); + my $res= run_mysqltest($tinfo); if ( $res == 0 ) { @@ -1973,9 +1974,8 @@ sub stop_slaves () { } -sub run_mysqltest ($$) { +sub run_mysqltest ($) { my $tinfo= shift; - my $master_opts= shift; my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . "--socket=$master->[0]->{'path_mysock'} --password="; diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index a854cf4c7b0..b02f85132aa 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -160,6 +160,21 @@ t1 CREATE TABLE `t1` ( `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END +nobug +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug CREATE TABLE t1 (EMPNUM INT); INSERT INTO t1 VALUES (0), (2); CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index f2cfce9085d..e942333d5fe 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -111,6 +111,17 @@ explain extended SELECT SHOW CREATE TABLE t1; DROP TABLE t1; +# Test for BUG#10151 +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; + # # Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL # diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5a2e14eef2e..0442865b7f9 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1420,6 +1420,8 @@ Item *Item_func_case::find_item(String *str) my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; + char buff[MAX_FIELD_WIDTH]; + String buff_str(buff,sizeof(buff),default_charset()); /* These will be initialized later */ LINT_INIT(first_expr_str); @@ -1433,7 +1435,7 @@ Item *Item_func_case::find_item(String *str) { case STRING_RESULT: // We can't use 'str' here as this may be overwritten - if (!(first_expr_str= args[first_expr_num]->val_str(&str_value))) + if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str))) return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible break; case INT_RESULT: diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 29cee6da4d3..825ec34e410 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -509,7 +509,7 @@ sp_head::destroy() delete i; delete_dynamic(&m_instr); m_pcont->destroy(); - free_items(free_list); + free_items(); /* If we have non-empty LEX stack then we just came out of parser with @@ -596,7 +596,6 @@ sp_head::execute(THD *thd) ctx->clear_handler(); thd->query_error= 0; old_arena= thd->current_arena; - thd->current_arena= this; /* We have to save/restore this info when we are changing call level to @@ -636,23 +635,18 @@ sp_head::execute(THD *thd) break; DBUG_PRINT("execute", ("Instruction %u", ip)); thd->set_time(); // Make current_time() et al work - { - /* - We have to substitute free_list of executing statement to - current_arena to store there all new items created during execution - (for example '*' expanding, or items made during permanent subquery - transformation) - Note: Every statement have to have all its items listed in free_list - for correct cleaning them up - */ - Item *save_free_list= thd->current_arena->free_list; - thd->current_arena->free_list= i->free_list; - ret= i->execute(thd, &ip); - i->free_list= thd->current_arena->free_list; - thd->current_arena->free_list= save_free_list; - } + /* + We have to set thd->current_arena before executing the instruction + to store in the instruction free_list all new items, created + during the first execution (for example expanding of '*' or the + items made during other permanent subquery transformations). + */ + thd->current_arena= i; + ret= i->execute(thd, &ip); if (i->free_list) cleanup_items(i->free_list); + i->state= Query_arena::EXECUTED; + // Check if an exception has occurred and a handler has been found // Note: We havo to check even if ret==0, since warnings (and some // errors don't return a non-zero value. @@ -694,7 +688,6 @@ sp_head::execute(THD *thd) DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; - cleanup_items(thd->current_arena->free_list); thd->current_arena= old_arena; state= EXECUTED; @@ -728,8 +721,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *nctx = NULL; uint i; int ret; - MEM_ROOT *old_mem_root, call_mem_root; - Item *old_free_list, *call_free_list; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; if (argcount != params) { @@ -741,14 +734,12 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - old_mem_root= thd->mem_root; - thd->mem_root= &call_mem_root; - old_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one + + thd->set_n_backup_item_arena(&call_arena, &backup_arena); // QQ Should have some error checking here? (types, etc...) nctx= new sp_rcontext(csize, hmax, cmax); - nctx->callers_mem_root= old_mem_root; + nctx->callers_mem_root= backup_arena.mem_root; for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -780,9 +771,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) // Partially restore context now. // We still need the call mem root and free list for processing // of the result. - call_free_list= thd->free_list; - thd->free_list= old_free_list; - thd->mem_root= old_mem_root; + thd->restore_backup_item_arena(&call_arena, &backup_arena); if (m_type == TYPE_ENUM_FUNCTION && ret == 0) { @@ -802,8 +791,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) thd->spcont= octx; // Now get rid of the rest of the callee context - cleanup_items(call_free_list); - free_items(call_free_list); + call_arena.free_items(); free_root(&call_mem_root, MYF(0)); DBUG_RETURN(ret); @@ -835,8 +823,8 @@ sp_head::execute_procedure(THD *thd, List *args) sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx - MEM_ROOT *old_mem_root, call_mem_root; - Item *old_free_list, *call_free_list; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; if (args->elements != params) { @@ -846,10 +834,7 @@ sp_head::execute_procedure(THD *thd, List *args) } init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - old_mem_root= thd->mem_root; - thd->mem_root= &call_mem_root; - old_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one + thd->set_n_backup_item_arena(&call_arena, &backup_arena); if (csize > 0 || hmax > 0 || cmax > 0) { @@ -919,9 +904,7 @@ sp_head::execute_procedure(THD *thd, List *args) // Partially restore context now. // We still need the call mem root and free list for processing // of out parameters. - call_free_list= thd->free_list; - thd->free_list= old_free_list; - thd->mem_root= old_mem_root; + thd->restore_backup_item_arena(&call_arena, &backup_arena); if (!ret && csize > 0) { @@ -996,8 +979,7 @@ sp_head::execute_procedure(THD *thd, List *args) thd->spcont= octx; // Now get rid of the rest of the callee context - cleanup_items(call_free_list); - free_items(call_free_list); + call_arena.free_items(); thd->lex->unit.cleanup(); free_root(&call_mem_root, MYF(0)); @@ -1291,6 +1273,13 @@ void sp_head::add_instr(sp_instr *instr) { instr->free_list= m_thd->free_list; m_thd->free_list= 0; + /* + Memory root of every instruction is designated for permanent + transformations (optimizations) made on the parsed tree during + the first execution. It points to the memory root of the + entire stored procedure, as their life span is equal. + */ + instr->mem_root= &main_mem_root; insert_dynamic(&m_instr, (gptr)&instr); } diff --git a/sql/sp_head.h b/sql/sp_head.h index 2c75a320f30..aaef5a3d50e 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -274,7 +274,7 @@ private: // "Instructions"... // -class sp_instr : public Sql_alloc +class sp_instr :public Query_arena, public Sql_alloc { sp_instr(const sp_instr &); /* Prevent use of these */ void operator=(sp_instr &); @@ -282,17 +282,16 @@ class sp_instr : public Sql_alloc public: uint marked; - Item *free_list; // My Items uint m_ip; // My index sp_pcontext *m_ctx; // My parse context // Should give each a name or type code for debugging purposes? sp_instr(uint ip, sp_pcontext *ctx) - :Sql_alloc(), marked(0), free_list(0), m_ip(ip), m_ctx(ctx) + :Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx) {} virtual ~sp_instr() - { free_items(free_list); } + { free_items(); } // Execute this instrution. '*nextp' will be set to the index of the next // instruction to execute. (For most instruction this will be the diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8abd7cbbe7d..20f48da9283 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -171,9 +171,6 @@ THD::THD() spcont(NULL) { current_arena= this; -#ifndef DBUG_OFF - backup_arena= 0; -#endif host= user= priv_user= db= ip= 0; catalog= (char*)"std"; // the only catalog we have for now host_or_ip= "connecting host"; @@ -528,7 +525,7 @@ void THD::cleanup_after_query() next_insert_id= 0; } /* Free Items that were created during this execution */ - free_items(free_list); + free_items(); /* In the rest of code we assume that free_list never points to garbage: Keep this predicate true. @@ -1485,6 +1482,21 @@ Query_arena::Type Query_arena::type() const } +void Query_arena::free_items() +{ + Item *next; + DBUG_ENTER("Query_arena::free_items"); + /* This works because items are allocated with sql_alloc() */ + for (; free_list; free_list= next) + { + next= free_list->next; + free_list->delete_self(); + } + /* Postcondition: free_list is 0 */ + DBUG_VOID_RETURN; +} + + /* Statement functions */ @@ -1556,11 +1568,11 @@ void THD::end_statement() void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::set_n_backup_item_arena"); - DBUG_ASSERT(backup_arena == 0); + DBUG_ASSERT(backup->is_backup_arena == FALSE); backup->set_item_arena(this); set_item_arena(set); #ifndef DBUG_OFF - backup_arena= 1; + backup->is_backup_arena= TRUE; #endif DBUG_VOID_RETURN; } @@ -1569,10 +1581,11 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::restore_backup_item_arena"); + DBUG_ASSERT(backup->is_backup_arena); set->set_item_arena(this); set_item_arena(backup); #ifndef DBUG_OFF - backup_arena= 0; + backup->is_backup_arena= FALSE; #endif DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index a635a126f84..adc164085f9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -663,7 +663,10 @@ public: Item *free_list; MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF - bool backup_arena; + bool is_backup_arena; /* True if this arena is used for backup. */ +#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 +#else +#define INIT_ARENA_DBUG_INFO #endif enum enum_state { @@ -681,12 +684,14 @@ public: Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : free_list(0), mem_root(mem_root_arg), state(state_arg) - {} + { INIT_ARENA_DBUG_INFO; } /* This constructor is used only when Query_arena is created as backup storage for another instance of Query_arena. */ - Query_arena() {}; + Query_arena() { INIT_ARENA_DBUG_INFO; } + +#undef INIT_ARENA_DBUG_INFO virtual Type type() const; virtual ~Query_arena() {}; @@ -726,6 +731,8 @@ public: void set_n_backup_item_arena(Query_arena *set, Query_arena *backup); void restore_backup_item_arena(Query_arena *set, Query_arena *backup); void set_item_arena(Query_arena *set); + + void free_items(); }; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index eeea493d868..c97cb037f15 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2429,7 +2429,7 @@ Prepared_statement::~Prepared_statement() { if (cursor) cursor->Cursor::~Cursor(); - free_items(free_list); + free_items(); delete lex->result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1487dfbb436..96a25c7919b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1914,8 +1914,7 @@ Cursor::close() } join= 0; unit= 0; - free_items(free_list); - free_list= 0; + free_items(); /* Must be last, as some memory might be allocated for free purposes, like in free_tmp_table() (TODO: fix this issue)