diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 498c7ccf5eda04e5723ccb8fdbfc80c2c2b31bf0..93efb4a8cb6b3c7631b4639c0b531bdf152086c2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -337,8 +337,8 @@ while test $# -gt 0; do ;; --valgrind) VALGRIND="valgrind --alignment=8 --leak-check=yes --num-callers=16" - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc" - EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc" + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb" SLEEP_TIME_AFTER_RESTART=10 SLEEP_TIME_FOR_DELETE=120 USE_RUNNING_SERVER="" diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index d94ab6f57c37d31728365f174c48e0098122ba6b..d7c41d5dbc4bcb09a2aa45a058b3381f985970fd 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -30,6 +30,7 @@ explain select * from t1 where i=@vv1; table type possible_keys key key_len ref rows Extra t1 ref i i 4 const 1 Using where drop table t1,t2; +set @a=0,@b=0; select @a:=10, @b:=1, @a > @b, @a < @b; @a:=10 @b:=1 @a > @b @a < @b 10 1 1 0 @@ -38,18 +39,18 @@ select @a:="10", @b:="1", @a > @b, @a < @b; 10 1 1 0 select @a:=10, @b:=2, @a > @b, @a < @b; @a:=10 @b:=2 @a > @b @a < @b -10 2 1 0 +10 2 0 1 select @a:="10", @b:="2", @a > @b, @a < @b; @a:="10" @b:="2" @a > @b @a < @b -10 2 0 1 +10 2 1 0 select @a:=1; @a:=1 1 select @a, @a:=1; @a @a:=1 1 1 -create table t1 (id int); -insert into t1 values (1); +create table t1 (id int, d double, c char(10)); +insert into t1 values (1,2.0, "test"); select @c:=0; @c:=0 0 @@ -70,7 +71,29 @@ select @c:=0; select @c:=@c+1; @c:=@c+1 1 +select @d,(@d:=id),@d from t1; +@d (@d:=id) @d +NULL 1 1 +select @e,(@e:=d),@e from t1; +@e (@e:=d) @e +NULL 2 2 +select @f,(@f:=c),@f from t1; +@f (@f:=c) @f +NULL test test +set @g=1; +select @g,(@g:=c),@g from t1; +@g (@g:=c) @g +1 test test +select @c, @d, @e, @f; +@c @d @e @f +1 1 2 test +select @d:=id, @e:=id, @f:=id, @g:=@id from t1; +@d:=id @e:=id @f:=id @g:=@id +1 1 1 NULL +select @c, @d, @e, @f, @g; +@c @d @e @f @g +1 1 1 1 NULL drop table t1; select @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b, @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b; @a:=10 @b:=2 @a>@b @a:="10" @b:="2" @a>@b @a:=10 @b:=2 @a>@b @a:="10" @b:="2" @a>@b -10 2 1 10 2 0 10 2 1 10 2 0 +10 2 1 10 2 1 10 2 1 10 2 1 diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 1e466c149bb75520bffeb846afddc112ea43468d..56528405a2a30976ccf68337be2b7e3e101fd498 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -19,8 +19,11 @@ explain select * from t1 where i=@vv1; drop table t1,t2; # Check types of variables +set @a=0,@b=0; select @a:=10, @b:=1, @a > @b, @a < @b; +# Note that here a and b will be avaluated as number select @a:="10", @b:="1", @a > @b, @a < @b; +# Note that here a and b will be avaluated as strings select @a:=10, @b:=2, @a > @b, @a < @b; select @a:="10", @b:="2", @a > @b, @a < @b; @@ -28,8 +31,8 @@ select @a:="10", @b:="2", @a > @b, @a < @b; select @a:=1; select @a, @a:=1; -create table t1 (id int); -insert into t1 values (1); +create table t1 (id int, d double, c char(10)); +insert into t1 values (1,2.0, "test"); select @c:=0; update t1 SET id=(@c:=@c+1); select @c; @@ -38,7 +41,15 @@ update t1 set id=(@c:=@c+1); select @c; select @c:=0; select @c:=@c+1; +select @d,(@d:=id),@d from t1; +select @e,(@e:=d),@e from t1; +select @f,(@f:=c),@f from t1; +set @g=1; +select @g,(@g:=c),@g from t1; +select @c, @d, @e, @f; +select @d:=id, @e:=id, @f:=id, @g:=@id from t1; +select @c, @d, @e, @f, @g; drop table t1; -# just fof fun :) -select @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b, @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b; \ No newline at end of file +# just for fun :) +select @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b, @a:=10, @b:=2, @a>@b, @a:="10", @b:="2", @a>@b; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4e1cc3865bad9d6591eceeee2347994cc086f4de..fd6d17d0cf2d940a84abfa7eacdb2d11e5ef2c10 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1835,8 +1835,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables) if (Item_func::fix_fields(thd,tables) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; - entry->type= cached_result_type; - entry->update_query_id=thd->query_id; + entry->update_query_id= thd->query_id; + cached_result_type= args[0]->result_type(); return 0; } @@ -1847,10 +1847,10 @@ Item_func_set_user_var::fix_length_and_dec() maybe_null=args[0]->maybe_null; max_length=args[0]->max_length; decimals=args[0]->decimals; - cached_result_type=args[0]->result_type(); } -void Item_func_set_user_var::update_hash(void *ptr, uint length, + +bool Item_func_set_user_var::update_hash(const void *ptr, uint length, Item_result type) { if ((null_value=args[0]->null_value)) @@ -1863,6 +1863,8 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, } else { + if (type == STRING_RESULT) + length++; // Store strings with end \0 if (length <= extra_size) { /* Save value in value struct */ @@ -1887,73 +1889,151 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, goto err; } } + if (type == STRING_RESULT) + { + length--; // Fix length change above + entry->value[length]= 0; // Store end \0 + } memcpy(entry->value,ptr,length); entry->length= length; entry->type=type; } - return; + return 0; err: current_thd->fatal_error=1; // Probably end of memory null_value=1; - return; + return 1; // Error } -bool -Item_func_set_user_var::update() + +/* Get the value of a variable as a double */ + +double user_var_entry::val(my_bool *null_value) { - DBUG_ENTER("Item_func_set_user_var::update"); - switch (cached_result_type) { - case REAL_RESULT: (void)native_val(); break; - case INT_RESULT: (void)native_val_int(); break; - case STRING_RESULT: (void)native_val_str(); break; + if ((*null_value= (value == 0))) + return 0.0; + + switch (type) { + case REAL_RESULT: + return *(double*) value; + case INT_RESULT: + return (double) *(longlong*) value; + case STRING_RESULT: + return atof(value); // This is null terminated } - DBUG_RETURN(current_thd->fatal_error); + return 0.0; // Impossible } -double -Item_func_set_user_var::val() +/* Get the value of a variable as an integer */ + +longlong user_var_entry::val_int(my_bool *null_value) { - DBUG_ENTER("Item_func_set_user_var::val"); - switch (cached_result_type) { - case REAL_RESULT: return native_val(); break; - case INT_RESULT: return native_val_int(); break; + if ((*null_value= (value == 0))) + return LL(0); + + switch (type) { + case REAL_RESULT: + return (longlong) *(double*) value; + case INT_RESULT: + return *(longlong*) value; case STRING_RESULT: - { - String *res= native_val_str(); - return !res ? 0 : atof(res->c_ptr()); + return strtoull(value,NULL,10); // String is null terminated } + return LL(0); // Impossible +} + + +/* Get the value of a variable as a string */ + +String *user_var_entry::val_str(my_bool *null_value, String *str, + uint decimals) +{ + if ((*null_value= (value == 0))) + return (String*) 0; + + switch (type) { + case REAL_RESULT: + str->set(*(double*) value, decimals); + break; + case INT_RESULT: + str->set(*(longlong*) value); + break; + case STRING_RESULT: + if (str->copy(value, length)) + str= 0; // EOM error } - DBUG_RETURN(args[0]->val()); + return(str); } -longlong -Item_func_set_user_var::val_int() + +/* + This functions is invoked on SET @variable or @variable:= expression. + + SYNOPSIS + Item_func_set_user_var::update() + + NOTES + We have to store the expression as such in the variable, independent of + the value method used by the user + + RETURN + 0 Ok + 1 EOM Error + +*/ + + +bool +Item_func_set_user_var::update() { - DBUG_ENTER("Item_func_set_user_var::val_int"); + bool res; + DBUG_ENTER("Item_func_set_user_var::update"); + LINT_INIT(res); + switch (cached_result_type) { - case REAL_RESULT: return (longlong)native_val(); break; - case INT_RESULT: return native_val_int(); break; - case STRING_RESULT: + case REAL_RESULT: { - String *res= native_val_str(); - return !res ? 0 : strtoull(res->c_ptr(),NULL,10); + double value=args[0]->val(); + res= update_hash((void*) &value,sizeof(value), REAL_RESULT); + break; } + case INT_RESULT: + { + longlong value=args[0]->val_int(); + res= update_hash((void*) &value,sizeof(longlong), INT_RESULT); + break; } - DBUG_RETURN(args[0]->val_int()); + case STRING_RESULT: + String *tmp; + tmp=args[0]->val_str(&value); + if (!tmp) // Null value + res= update_hash((void*) 0,0,STRING_RESULT); + else + res= update_hash((void*) tmp->ptr(),tmp->length(),STRING_RESULT); + break; + } + DBUG_RETURN(res); } -String * -Item_func_set_user_var::val_str(String *str) + +double Item_func_set_user_var::val() { - DBUG_ENTER("Item_func_set_user_var::val_str"); - switch (cached_result_type) { - case REAL_RESULT: str->set(native_val(),decimals); break; - case INT_RESULT: str->set(native_val_int(),decimals); break; - case STRING_RESULT: str= native_val_str(str); break; - } - DBUG_RETURN(str); + update(); // Store expression + return entry->val(&null_value); +} + +longlong Item_func_set_user_var::val_int() +{ + update(); // Store expression + return entry->val_int(&null_value); +} + +String *Item_func_set_user_var::val_str(String *str) +{ + update(); // Store expression + return entry->val_str(&null_value, str, decimals); } @@ -1967,75 +2047,30 @@ void Item_func_set_user_var::print(String *str) } -user_var_entry *Item_func_get_user_var::get_entry() -{ - if (!var_entry || ! var_entry->value) - { - null_value=1; - return 0; - } - null_value=0; - return var_entry; -} - String * Item_func_get_user_var::val_str(String *str) { DBUG_ENTER("Item_func_get_user_var::val_str"); - user_var_entry *entry=get_entry(); - if (!entry) - return NULL; - switch (entry->type) { - case REAL_RESULT: - str->set(*(double*) entry->value,decimals); - break; - case INT_RESULT: - str->set(*(longlong*) entry->value); - break; - case STRING_RESULT: - if (str->copy(entry->value, entry->length-1)) - { - null_value=1; - return NULL; - } - break; - } - DBUG_RETURN(str); + if (!var_entry) + return (String*) 0; // No such variable + DBUG_RETURN(var_entry->val_str(&null_value, str, decimals)); } double Item_func_get_user_var::val() { - user_var_entry *entry=get_entry(); - if (!entry) - return 0.0; - switch (entry->type) { - case REAL_RESULT: - return *(double*) entry->value; - case INT_RESULT: - return (double) *(longlong*) entry->value; - case STRING_RESULT: - return atof(entry->value); // This is null terminated - } - return 0.0; // Impossible + if (!var_entry) + return 0.0; // No such variable + return (var_entry->val(&null_value)); } longlong Item_func_get_user_var::val_int() { - user_var_entry *entry=get_entry(); - if (!entry) - return LL(0); - switch (entry->type) { - case REAL_RESULT: - return (longlong) *(double*) entry->value; - case INT_RESULT: - return *(longlong*) entry->value; - case STRING_RESULT: - return strtoull(entry->value,NULL,10); // String is null terminated - } - return LL(0); // Impossible + if (!var_entry) + return LL(0); // No such variable + return (var_entry->val_int(&null_value)); } @@ -2045,12 +2080,15 @@ void Item_func_get_user_var::fix_length_and_dec() maybe_null=1; decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - var_entry= get_variable(&thd->user_vars, name, 0); + if (!(var_entry= get_variable(&thd->user_vars, name, 0))) + null_value= 1; } bool Item_func_get_user_var::const_item() const -{ return var_entry && current_thd->query_id != var_entry->update_query_id; } +{ + return var_entry && current_thd->query_id != var_entry->update_query_id; +} enum Item_result Item_func_get_user_var::result_type() const diff --git a/sql/item_func.h b/sql/item_func.h index ffc587c3cf3bb557645ab06eb700bf7af040b243..09aba9694dd443b00d6f134d588029ec48d0b933 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -888,45 +888,16 @@ class Item_func_set_user_var :public Item_func enum Item_result cached_result_type; LEX_STRING name; user_var_entry *entry; - - double native_val() - { - double value=args[0]->val(); - update_hash((void*) &value,sizeof(value), REAL_RESULT); - return value; - } - - longlong native_val_int() - { - longlong value=args[0]->val_int(); - update_hash((void*) &value,sizeof(longlong),INT_RESULT); - return value; - } - - String *native_val_str(String *str) - { - char buffer[MAX_FIELD_WIDTH]; - String *res=args[0]->val_str(str); - if (!res) // Null value - update_hash((void*) 0,0,STRING_RESULT); - else - update_hash(res->c_ptr(),res->length()+1,STRING_RESULT); - return res; - } - - String *native_val_str() - { - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer,sizeof(buffer)); - return native_val_str(&tmp); - } + char buffer[MAX_FIELD_WIDTH]; + String value; public: - Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {} + Item_func_set_user_var(LEX_STRING a,Item *b): + Item_func(b), name(a), value(buffer,sizeof(buffer)) {} double val(); longlong val_int(); String *val_str(String *str); - void update_hash(void *ptr, uint length, enum Item_result type); + bool update_hash(const void *ptr, uint length, enum Item_result type); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd,struct st_table_list *tables); @@ -945,7 +916,6 @@ class Item_func_get_user_var :public Item_func public: Item_func_get_user_var(LEX_STRING a): Item_func(), name(a) {} - user_var_entry *get_entry(); double val(); longlong val_int(); String *val_str(String* str); diff --git a/sql/log.cc b/sql/log.cc index 6307ac0c11ed3c55e376e2a3faab2d397db904c6..33ca82aa14fe040a6940be1948c447430d6a9df5 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1315,9 +1315,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback) /* Now this Query_log_event has artificial log_pos 0. It must be adjusted to reflect the real position in the log. Not doing it would confuse the - slave: it would prevent this one from knowing where he is in the master's - binlog, which would result in wrong positions being shown to the user, - MASTER_POS_WAIT undue waiting etc. + slave: it would prevent this one from knowing where he is in the + master's binlog, which would result in wrong positions being shown to + the user, MASTER_POS_WAIT undue waiting etc. */ qinfo.set_log_pos(this); if (qinfo.write(&log_file)) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bcf115fecccc2eb21c8117278f65b64b0b1c232e..1bb51ea8e915d9cc224b212981a867102c82ef5e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -55,7 +55,9 @@ char pstack_file_name[80]; #endif /* __linux__ */ -#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) +/* We have HAVE_purify below as this speeds up the shutdown of MySQL */ + +#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) || defined(HAVE_purify) && defined(__linux__) #define HAVE_CLOSE_SERVER_SOCK 1 #endif @@ -534,12 +536,14 @@ static void close_connections(void) struct timespec abstime; int error; LINT_INIT(error); + DBUG_PRINT("info",("Waiting for select_thread")); + #ifndef DONT_USE_THR_ALARM if (pthread_kill(select_thread,THR_CLIENT_ALARM)) break; // allready dead #endif set_timespec(abstime, 2); - for (uint tmp=0 ; tmp < 10 ; tmp++) + for (uint tmp=0 ; tmp < 10 && select_thread_in_use; tmp++) { error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count, &abstime); @@ -700,8 +704,8 @@ static void close_server_sock() VOID(shutdown(tmp_sock,2)); #if defined(__NETWARE__) /* - The following code is disabled for normal systems as it causes MySQL - AIX 4.3 during shutdown (not tested, but likely) + The following code is disabled for normal systems as it may cause MySQL + to hang on AIX 4.3 during shutdown */ DBUG_PRINT("info",("calling closesocket on unix/IP socket")); VOID(closesocket(tmp_sock)); diff --git a/sql/sql_class.h b/sql/sql_class.h index 8aa3d48bc35932c7037265441e651e44fa9837da..2ed9cb7b87707db95f155527b442a467d737b1dd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -783,8 +783,13 @@ class user_var_entry char *value; ulong length, update_query_id; Item_result type; + + double val(my_bool *null_value); + longlong val_int(my_bool *null_value); + String *val_str(my_bool *null_value, String *str, uint decimals); }; + /* Class for unique (removing of duplicates) */ class Unique :public Sql_alloc