diff options
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r-- | sql/sql_class.cc | 248 |
1 files changed, 187 insertions, 61 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc index bab81d785c3..ae2261e19f9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -36,6 +36,9 @@ #endif #include <mysys_err.h> +#include "sp_rcontext.h" +#include "sp_cache.h" + /* The following is used to initialise Table_ident with a internal table name @@ -157,18 +160,22 @@ bool foreign_key_prefix(Key *a, Key *b) THD::THD() :user_time(0), global_read_lock(0), is_fatal_error(0), - last_insert_id_used(0), - insert_id_used(0), rand_used(0), time_zone_used(0), - in_lock_tables(0), bootstrap(0) + rand_used(0), time_zone_used(0), + last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), + in_lock_tables(0), bootstrap(0), spcont(NULL) { current_arena= this; - host= user= priv_user= db= ip=0; +#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"; locked=some_tables_deleted=no_errors=password= 0; - killed=0; query_start_used= 0; count_cuted_fields= CHECK_FIELD_IGNORE; - db_length= col_access= 0; + killed= NOT_KILLED; + db_length= col_access=0; query_error= tmp_table_used= 0; next_insert_id=last_insert_id=0; open_tables= temporary_tables= handler_tables= derived_tables= 0; @@ -197,7 +204,7 @@ THD::THD() #endif net.last_error[0]=0; // If error on boot ull=0; - system_thread=cleanup_done=0; + system_thread= cleanup_done= abort_on_warning= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.changed_tables = 0; #ifdef __WIN__ @@ -224,9 +231,12 @@ THD::THD() /* Initialize sub structures */ init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); user_connect=(USER_CONN *)0; - hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, + hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, - (hash_free_key) free_user_var,0); + (hash_free_key) free_user_var, 0); + + sp_proc_cache= NULL; + sp_func_cache= NULL; /* For user vars replication*/ if (opt_bin_log) @@ -254,7 +264,7 @@ THD::THD() if (open_cached_file(&transaction.trans_log, mysql_tmpdir, LOG_PREFIX, binlog_cache_size, MYF(MY_WME))) - killed=1; + killed= KILL_CONNECTION; transaction.trans_log.end_of_file= max_binlog_cache_size; } #endif @@ -295,6 +305,7 @@ void THD::init(void) bzero((char*) warn_count, sizeof(warn_count)); total_warn_count= 0; update_charset(); + bzero((char *) &status_var, sizeof(status_var)); } @@ -333,9 +344,11 @@ void THD::change_user(void) cleanup_done= 0; init(); stmt_map.reset(); - hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, + hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, (hash_free_key) free_user_var, 0); + sp_cache_clear(&sp_proc_cache); + sp_cache_clear(&sp_func_cache); } @@ -359,6 +372,8 @@ void THD::cleanup(void) my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); delete_dynamic(&user_var_events); hash_free(&user_vars); + sp_cache_clear(&sp_proc_cache); + sp_cache_clear(&sp_func_cache); if (global_read_lock) unlock_global_read_lock(this); if (ull) @@ -368,6 +383,7 @@ void THD::cleanup(void) pthread_mutex_unlock(&LOCK_user_locks); ull= 0; } + cleanup_done=1; DBUG_VOID_RETURN; } @@ -380,6 +396,7 @@ THD::~THD() /* Ensure that no one is using THD */ pthread_mutex_lock(&LOCK_delete); pthread_mutex_unlock(&LOCK_delete); + add_to_status(&global_status_var, &status_var); /* Close connection */ #ifndef EMBEDDED_LIBRARY @@ -399,6 +416,9 @@ THD::~THD() } #endif + sp_cache_clear(&sp_proc_cache); + sp_cache_clear(&sp_func_cache); + DBUG_PRINT("info", ("freeing host")); if (host != my_localhost) // If not pointer to constant safeFree(host); @@ -411,7 +431,7 @@ THD::~THD() mysys_var=0; // Safety (shouldn't be needed) pthread_mutex_destroy(&LOCK_delete); #ifndef DBUG_OFF - dbug_sentry = THD_SENTRY_GONE; + dbug_sentry= THD_SENTRY_GONE; #endif /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */ clear_alloc_root(&stmt_backup.main_mem_root); @@ -419,14 +439,35 @@ THD::~THD() } -void THD::awake(bool prepare_to_die) +/* + Add to one status variable another status variable + + NOTES + This function assumes that all variables are long/ulong. + If this assumption will change, then we have to explictely add + the other variables after the while loop +*/ + +void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var) +{ + ulong *end= (ulong*) ((byte*) to_var + offsetof(STATUS_VAR, + last_system_status_var) + + sizeof(ulong)); + ulong *to= (ulong*) to_var, *from= (ulong*) from_var; + + while (to != end) + *(to++)+= *(from++); +} + + +void THD::awake(THD::killed_state state_to_set) { THD_CHECK_SENTRY(this); safe_mutex_assert_owner(&LOCK_delete); - if (prepare_to_die) - killed = 1; - thr_alarm_kill(real_id); + killed= state_to_set; + if (state_to_set != THD::KILL_QUERY) + thr_alarm_kill(real_id); #ifdef SIGNAL_WITH_VIO_CLOSE close_active_vio(); #endif @@ -485,6 +526,24 @@ bool THD::store_globals() } +/* Cleanup after a query */ + +void THD::cleanup_after_query() +{ + if (clear_next_insert_id) + { + clear_next_insert_id= 0; + next_insert_id= 0; + } + /* Free Items that were created during this execution */ + free_items(free_list); + /* + In the rest of code we assume that free_list never points to garbage: + Keep this predicate true. + */ + free_list= 0; +} + /* Convert a string to another character set @@ -646,8 +705,8 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) if (!new_table) { my_error(EE_OUTOFMEMORY, MYF(ME_BELL), - ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1); - killed= 1; + ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1); + killed= KILL_CONNECTION; return 0; } @@ -674,15 +733,16 @@ int THD::send_explain_fields(select_result *result) item->maybe_null=1; field_list.push_back(item=new Item_empty_string("key", NAME_LEN, cs)); item->maybe_null=1; - field_list.push_back(item=new Item_return_int("key_len",3, - MYSQL_TYPE_LONGLONG)); + field_list.push_back(item=new Item_empty_string("key_len", + NAME_LEN*MAX_KEY)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("ref", NAME_LEN*MAX_REF_PARTS, cs)); item->maybe_null=1; field_list.push_back(new Item_return_int("rows", 10, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Extra", 255, cs)); - return (result->send_fields(field_list,1)); + return (result->send_fields(field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)); } #ifdef SIGNAL_WITH_VIO_CLOSE @@ -743,10 +803,13 @@ void THD::rollback_item_tree_changes() { I_List_iterator<Item_change_record> it(change_list); Item_change_record *change; + DBUG_ENTER("rollback_item_tree_changes"); + while ((change= it++)) *change->place= change->old_value; /* We can forget about changes memory: it's allocated in runtime memroot */ change_list.empty(); + DBUG_VOID_RETURN; } @@ -761,7 +824,7 @@ select_result::select_result() void select_result::send_error(uint errcode,const char *err) { - ::send_error(thd, errcode, err); + my_message(errcode, err, MYF(0)); } @@ -783,9 +846,9 @@ sql_exchange::sql_exchange(char *name,bool flag) escaped= &default_escaped; } -bool select_send::send_fields(List<Item> &list,uint flag) +bool select_send::send_fields(List<Item> &list, uint flags) { - return thd->protocol->send_fields(&list,flag); + return thd->protocol->send_fields(&list, flags); } /* Send data to client. Returns 0 if ok */ @@ -865,7 +928,7 @@ bool select_send::send_eof() void select_to_file::send_error(uint errcode,const char *err) { - ::send_error(thd,errcode,err); + my_message(errcode, err, MYF(0)); if (file > 0) { (void) end_io_cache(&cache); @@ -1189,7 +1252,7 @@ bool select_dump::send_data(List<Item> &items) } if (row_count++ > 1) { - my_error(ER_TOO_MANY_ROWS, MYF(0)); + my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0)); goto err; } while ((item=li++)) @@ -1202,7 +1265,7 @@ bool select_dump::send_data(List<Item> &items) } else if (my_b_write(&cache,(byte*) res->ptr(),res->length())) { - my_error(ER_ERROR_ON_WRITE,MYF(0), path, my_errno); + my_error(ER_ERROR_ON_WRITE, MYF(0), path, my_errno); goto err; } } @@ -1285,7 +1348,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items) bool select_max_min_finder_subselect::cmp_real() { Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); - double val1= cache->val(), val2= maxmin->val(); + double val1= cache->val_real(), val2= maxmin->val_real(); if (fmax) return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && @@ -1352,27 +1415,36 @@ bool select_exists_subselect::send_data(List<Item> &items) int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { List_iterator_fast<Item> li(list); - List_iterator_fast<LEX_STRING> gl(var_list); + List_iterator_fast<my_var> gl(var_list); Item *item; - LEX_STRING *ls; + + local_vars.empty(); // Clear list if SP + unit= u; + row_count= 0; + if (var_list.elements != list.elements) { - my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0)); + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0)); return 1; } - unit=u; while ((item=li++)) { - ls= gl++; - Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item); - /* - Item_func_set_user_var can't substitute something else on its place => - 0 can be passed as last argument (reference on item) - */ - xx->fix_fields(thd,(TABLE_LIST*) thd->lex->select_lex.table_list.first, - 0); - xx->fix_length_and_dec(); - vars.push_back(xx); + my_var *mv= gl++; + if (mv->local) + (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); + else + { + Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item); + /* + Item_func_set_user_var can't substitute something else on its place => + 0 can be passed as last argument (reference on item) + */ + xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, + 0); + xx->fix_length_and_dec(); + vars.push_back(xx); + } } return 0; } @@ -1433,7 +1505,7 @@ Item_arena::Item_arena(bool init_mem_root) Item_arena::Type Item_arena::type() const { - DBUG_ASSERT("Item_arena::type()" == "abstract"); + DBUG_ASSERT(0); /* Should never be called */ return STATEMENT; } @@ -1449,7 +1521,8 @@ Statement::Statement(THD *thd) allow_sum_func(0), lex(&main_lex), query(0), - query_length(0) + query_length(0), + cursor(0) { name.str= NULL; } @@ -1467,7 +1540,8 @@ Statement::Statement() allow_sum_func(0), /* initialized later */ lex(&main_lex), query(0), /* these two are set */ - query_length(0) /* in alloc_query() */ + query_length(0), /* in alloc_query() */ + cursor(0) { } @@ -1486,6 +1560,7 @@ void Statement::set_statement(Statement *stmt) lex= stmt->lex; query= stmt->query; query_length= stmt->query_length; + cursor= stmt->cursor; } @@ -1510,8 +1585,8 @@ void THD::end_statement() lex_end(lex); delete lex->result; lex->result= 0; - free_items(free_list); - free_list= 0; + /* Note that free_list is freed in cleanup_after_query() */ + /* Don't free mem_root, as mem_root is freed in the end of dispatch_command (once for any command). @@ -1522,8 +1597,12 @@ void THD::end_statement() void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup) { DBUG_ENTER("Item_arena::set_n_backup_item_arena"); + DBUG_ASSERT(backup_arena == 0); backup->set_item_arena(this); set_item_arena(set); +#ifndef DBUG_OFF + backup_arena= 1; +#endif DBUG_VOID_RETURN; } @@ -1533,6 +1612,9 @@ void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup) DBUG_ENTER("Item_arena::restore_backup_item_arena"); set->set_item_arena(this); set_item_arena(backup); +#ifndef DBUG_OFF + backup_arena= 0; +#endif #ifdef NOT_NEEDED_NOW /* Reset backup mem_root to avoid its freeing. @@ -1623,8 +1705,19 @@ int Statement_map::insert(Statement *statement) bool select_dumpvar::send_data(List<Item> &items) { List_iterator_fast<Item_func_set_user_var> li(vars); + List_iterator_fast<Item_splocal> var_li(local_vars); + List_iterator_fast<my_var> my_li(var_list); + List_iterator_fast<Item> it(items); Item_func_set_user_var *xx; + Item_splocal *yy; + Item *item; + my_var *zz; DBUG_ENTER("send_data"); + if (unit->offset_limit_cnt) + { // using limit offset,count + unit->offset_limit_cnt--; + DBUG_RETURN(0); + } if (unit->offset_limit_cnt) { // Using limit offset,count @@ -1633,29 +1726,37 @@ bool select_dumpvar::send_data(List<Item> &items) } if (row_count++) { - my_error(ER_TOO_MANY_ROWS, MYF(0)); + my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0)); DBUG_RETURN(1); } - while ((xx=li++)) + while ((zz=my_li++) && (item=it++)) { - xx->check(); - xx->update(); + if (zz->local) + { + if ((yy=var_li++)) + { + if (thd->spcont->set_item_eval(yy->get_offset(), item, zz->type)) + DBUG_RETURN(1); + } + } + else + { + if ((xx=li++)) + { + xx->check(); + xx->update(); + } + } } DBUG_RETURN(0); } bool select_dumpvar::send_eof() { - if (row_count) - { - ::send_ok(thd,row_count); - return 0; - } - else - { - my_error(ER_EMPTY_QUERY,MYF(0)); - return 1; - } + if (! row_count) + send_warning(thd, ER_SP_FETCH_NO_DATA); + ::send_ok(thd,row_count); + return 0; } /**************************************************************************** @@ -1667,4 +1768,29 @@ void TMP_TABLE_PARAM::init() field_count= sum_func_count= func_count= hidden_field_count= 0; group_parts= group_length= group_null_parts= 0; quick_group= 1; + table_charset= 0; +} + + +void thd_increment_bytes_sent(ulong length) +{ + current_thd->status_var.bytes_sent+= length; +} + + +void thd_increment_bytes_received(ulong length) +{ + current_thd->status_var.bytes_received+= length; +} + + +void thd_increment_net_big_packet_count(ulong length) +{ + current_thd->status_var.net_big_packet_count+= length; +} + + +void THD::set_status_var_init() +{ + bzero((char*) &status_var, sizeof(status_var)); } |