summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc248
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));
}