diff options
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 830 |
1 files changed, 352 insertions, 478 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index ed457adcff9..4df7638370a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -769,13 +769,14 @@ void Item_num_op::find_num_type(void) { hybrid_type= DECIMAL_RESULT; result_precision(); + fix_decimals(); } else { DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); - decimals= 0; hybrid_type=INT_RESULT; result_precision(); + decimals= 0; } DBUG_PRINT("info", ("Type: %s", (hybrid_type == REAL_RESULT ? "REAL_RESULT" : @@ -1706,6 +1707,7 @@ void Item_func_div::fix_length_and_dec() break; case DECIMAL_RESULT: result_precision(); + fix_decimals(); break; case STRING_RESULT: case ROW_RESULT: @@ -1905,6 +1907,16 @@ longlong Item_func_neg::int_op() if (args[0]->unsigned_flag && (ulonglong) value > (ulonglong) LONGLONG_MAX + 1) return raise_integer_overflow(); + + if (value == LONGLONG_MIN) + { + if (args[0]->unsigned_flag != unsigned_flag) + /* negation of LONGLONG_MIN is LONGLONG_MIN. */ + return LONGLONG_MIN; + else + return raise_integer_overflow(); + } + return check_integer_overflow(-value, !args[0]->unsigned_flag && value < 0); } @@ -2201,7 +2213,7 @@ longlong Item_func_shift_left::val_int() return 0; } null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : LL(0)); + return (shift < sizeof(longlong)*8 ? (longlong) res : 0); } longlong Item_func_shift_right::val_int() @@ -2216,7 +2228,7 @@ longlong Item_func_shift_right::val_int() return 0; } null_value=0; - return (shift < sizeof(longlong)*8 ? (longlong) res : LL(0)); + return (shift < sizeof(longlong)*8 ? (longlong) res : 0); } @@ -3149,7 +3161,7 @@ void Item_func_find_in_set::fix_length_and_dec() find->length(), 0); enum_bit=0; if (enum_value) - enum_bit=LL(1) << (enum_value-1); + enum_bit=1LL << (enum_value-1); } } } @@ -3230,7 +3242,7 @@ longlong Item_func_find_in_set::val_int() wc == (my_wc_t) separator) return (longlong) ++position; else - return LL(0); + return 0; } } return 0; @@ -3736,120 +3748,6 @@ udf_handler::~udf_handler() bool udf_handler::get_arguments() { return 0; } #endif /* HAVE_DLOPEN */ -/* -** User level locks -*/ - -mysql_mutex_t LOCK_user_locks; -static HASH hash_user_locks; - -class User_level_lock -{ - uchar *key; - size_t key_length; - -public: - int count; - bool locked; - mysql_cond_t cond; - my_thread_id thread_id; - void set_thread(THD *thd) { thread_id= thd->thread_id; } - - User_level_lock(const uchar *key_arg,uint length, ulong id) - :key_length(length),count(1),locked(1), thread_id(id) - { - key= (uchar*) my_memdup(key_arg,length,MYF(0)); - mysql_cond_init(key_user_level_lock_cond, &cond, NULL); - if (key) - { - if (my_hash_insert(&hash_user_locks,(uchar*) this)) - { - my_free(key); - key=0; - } - } - } - ~User_level_lock() - { - if (key) - { - my_hash_delete(&hash_user_locks,(uchar*) this); - my_free(key); - } - mysql_cond_destroy(&cond); - } - inline bool initialized() { return key != 0; } - friend void item_user_lock_release(User_level_lock *ull); - friend uchar *ull_get_key(const User_level_lock *ull, size_t *length, - my_bool not_used); -}; - -uchar *ull_get_key(const User_level_lock *ull, size_t *length, - my_bool not_used __attribute__((unused))) -{ - *length= ull->key_length; - return ull->key; -} - -#ifdef HAVE_PSI_INTERFACE -static PSI_mutex_key key_LOCK_user_locks; - -static PSI_mutex_info all_user_mutexes[]= -{ - { &key_LOCK_user_locks, "LOCK_user_locks", PSI_FLAG_GLOBAL} -}; - -static void init_user_lock_psi_keys(void) -{ - const char* category= "sql"; - int count; - - if (PSI_server == NULL) - return; - - count= array_elements(all_user_mutexes); - PSI_server->register_mutex(category, all_user_mutexes, count); -} -#endif - -static bool item_user_lock_inited= 0; - -void item_user_lock_init(void) -{ -#ifdef HAVE_PSI_INTERFACE - init_user_lock_psi_keys(); -#endif - - mysql_mutex_init(key_LOCK_user_locks, &LOCK_user_locks, MY_MUTEX_INIT_SLOW); - my_hash_init(&hash_user_locks,system_charset_info, - 16,0,0,(my_hash_get_key) ull_get_key,NULL,0); - item_user_lock_inited= 1; -} - -void item_user_lock_free(void) -{ - if (item_user_lock_inited) - { - item_user_lock_inited= 0; - my_hash_free(&hash_user_locks); - mysql_mutex_destroy(&LOCK_user_locks); - } -} - -void item_user_lock_release(User_level_lock *ull) -{ - ull->locked=0; - ull->thread_id= 0; - if (--ull->count) - mysql_cond_signal(&ull->cond); - else - delete ull; -} - -/** - Wait until we are at or past the given position in the master binlog - on the slave. -*/ longlong Item_master_pos_wait::val_int() { @@ -3951,7 +3849,7 @@ class Interruptible_wait /** Time to wait before polling the connection status. */ -const ulonglong Interruptible_wait::m_interrupt_interval= 5 * ULL(1000000000); +const ulonglong Interruptible_wait::m_interrupt_interval= 5 * 1000000000ULL; /** @@ -3996,7 +3894,136 @@ int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex) /** - Get a user level lock. If the thread has an old lock this is first released. + For locks with EXPLICIT duration, MDL returns a new ticket + every time a lock is granted. This allows to implement recursive + locks without extra allocation or additional data structures, such + as below. However, if there are too many tickets in the same + MDL_context, MDL_context::find_ticket() is getting too slow, + since it's using a linear search. + This is why a separate structure is allocated for a user + level lock, and before requesting a new lock from MDL, + GET_LOCK() checks thd->ull_hash if such lock is already granted, + and if so, simply increments a reference counter. +*/ + +class User_level_lock +{ +public: + MDL_ticket *lock; + int refs; +}; + + +/** Extract a hash key from User_level_lock. */ + +uchar *ull_get_key(const uchar *ptr, size_t *length, + my_bool not_used __attribute__((unused))) +{ + User_level_lock *ull = (User_level_lock*) ptr; + MDL_key *key = ull->lock->get_key(); + *length= key->length(); + return (uchar*) key->ptr(); +} + + +/** + Release all user level locks for this THD. +*/ + +void mysql_ull_cleanup(THD *thd) +{ + User_level_lock *ull; + DBUG_ENTER("mysql_ull_cleanup"); + + for (uint i= 0; i < thd->ull_hash.records; i++) + { + ull = (User_level_lock*) my_hash_element(&thd->ull_hash, i); + thd->mdl_context.release_lock(ull->lock); + my_free(ull); + } + + my_hash_free(&thd->ull_hash); + + DBUG_VOID_RETURN; +} + + +/** + Set explicit duration for metadata locks corresponding to + user level locks to protect them from being released at the end + of transaction. +*/ + +void mysql_ull_set_explicit_lock_duration(THD *thd) +{ + User_level_lock *ull; + DBUG_ENTER("mysql_ull_set_explicit_lock_duration"); + + for (uint i= 0; i < thd->ull_hash.records; i++) + { + ull= (User_level_lock*) my_hash_element(&thd->ull_hash, i); + thd->mdl_context.set_lock_duration(ull->lock, MDL_EXPLICIT); + } + DBUG_VOID_RETURN; +} + + +/** + When MDL detects a lock wait timeout, it pushes + an error into the statement diagnostics area. + For GET_LOCK(), lock wait timeout is not an error, + but a special return value (0). NULL is returned in + case of error. + Capture and suppress lock wait timeout. +*/ + +class Lock_wait_timeout_handler: public Internal_error_handler +{ +public: + Lock_wait_timeout_handler() :m_lock_wait_timeout(false) {} + + bool m_lock_wait_timeout; + + bool handle_condition(THD * /* thd */, uint sql_errno, + const char * /* sqlstate */, + MYSQL_ERROR::enum_warning_level /* level */, + const char *message, + MYSQL_ERROR ** /* cond_hdl */); +}; + +bool +Lock_wait_timeout_handler:: +handle_condition(THD * /* thd */, uint sql_errno, + const char * /* sqlstate */, + MYSQL_ERROR::enum_warning_level /* level */, + const char *message, + MYSQL_ERROR ** /* cond_hdl */) +{ + if (sql_errno == ER_LOCK_WAIT_TIMEOUT) + { + m_lock_wait_timeout= true; + return true; /* condition handled */ + } + return false; +} + + +static int ull_name_ok(String *name) +{ + if (!name || !name->length()) + return 0; + + if (name->length() > NAME_LEN) + { + my_error(ER_TOO_LONG_IDENT, MYF(0), name->c_ptr_safe()); + return 0; + } + return 1; +} + + +/** + Get a user level lock. @retval 1 : Got lock @@ -4009,14 +4036,13 @@ int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex) longlong Item_func_get_lock::val_int() { DBUG_ASSERT(fixed == 1); - String *res=args[0]->val_str(&value); + String *res= args[0]->val_str(&value); ulonglong timeout= args[1]->val_int(); - THD *thd=current_thd; + THD *thd= current_thd; User_level_lock *ull; - int error; - Interruptible_wait timed_cond(thd); DBUG_ENTER("Item_func_get_lock::val_int"); + null_value= 1; /* In slave thread no need to get locks, everything is serialized. Anyway there is no way to make GET_LOCK() work on slave like it did on master @@ -4025,103 +4051,70 @@ longlong Item_func_get_lock::val_int() it's not guaranteed to be same as on master. */ if (thd->slave_thread) + { + null_value= 0; DBUG_RETURN(1); + } - mysql_mutex_lock(&LOCK_user_locks); - - if (!res || !res->length()) - { - mysql_mutex_unlock(&LOCK_user_locks); - null_value=1; + if (!ull_name_ok(res)) DBUG_RETURN(0); - } + DBUG_PRINT("info", ("lock %.*s, thd=%ld", res->length(), res->ptr(), (long) thd->real_id)); - null_value=0; - - if (thd->ull) + /* HASH entries are of type User_level_lock. */ + if (! my_hash_inited(&thd->ull_hash) && + my_hash_init(&thd->ull_hash, &my_charset_bin, + 16 /* small hash */, 0, 0, ull_get_key, NULL, 0)) { - item_user_lock_release(thd->ull); - thd->ull=0; - } - - if (!(ull= ((User_level_lock *) my_hash_search(&hash_user_locks, - (uchar*) res->ptr(), - (size_t) res->length())))) - { - ull= new User_level_lock((uchar*) res->ptr(), (size_t) res->length(), - thd->thread_id); - if (!ull || !ull->initialized()) - { - delete ull; - mysql_mutex_unlock(&LOCK_user_locks); - null_value=1; // Probably out of memory - DBUG_RETURN(0); - } - ull->set_thread(thd); - thd->ull=ull; - mysql_mutex_unlock(&LOCK_user_locks); - DBUG_PRINT("info", ("made new lock")); - DBUG_RETURN(1); // Got new lock + DBUG_RETURN(0); } - ull->count++; - DBUG_PRINT("info", ("ull->count=%d", ull->count)); - /* - Structure is now initialized. Try to get the lock. - Set up control struct to allow others to abort locks. - */ - THD_STAGE_INFO(thd, stage_user_lock); - thd->mysys_var->current_mutex= &LOCK_user_locks; - thd->mysys_var->current_cond= &ull->cond; + MDL_request ull_request; + ull_request.init(MDL_key::USER_LOCK, res->c_ptr_safe(), "", + MDL_SHARED_NO_WRITE, MDL_EXPLICIT); + MDL_key *ull_key = &ull_request.key; - timed_cond.set_timeout(timeout * ULL(1000000000)); - error= 0; - thd_wait_begin(thd, THD_WAIT_USER_LOCK); - while (ull->locked && !thd->killed) + if ((ull= (User_level_lock*) + my_hash_search(&thd->ull_hash, ull_key->ptr(), ull_key->length()))) { - DBUG_PRINT("info", ("waiting on lock")); - error= timed_cond.wait(&ull->cond, &LOCK_user_locks); - if (error == ETIMEDOUT || error == ETIME) - { - DBUG_PRINT("info", ("lock wait timeout")); - break; - } - error= 0; + /* Recursive lock */ + ull->refs++; + null_value = 0; + DBUG_RETURN(1); } - thd_wait_end(thd); - if (ull->locked) + Lock_wait_timeout_handler lock_wait_timeout_handler; + thd->push_internal_handler(&lock_wait_timeout_handler); + bool error= thd->mdl_context.acquire_lock(&ull_request, timeout); + (void) thd->pop_internal_handler(); + if (error) { - if (!--ull->count) - { - DBUG_ASSERT(0); - delete ull; // Should never happen - } - if (!error) // Killed (thd->killed != 0) - { - error=1; - null_value=1; // Return NULL - } + if (lock_wait_timeout_handler.m_lock_wait_timeout) + null_value= 0; + DBUG_RETURN(0); } - else // We got the lock + + ull= (User_level_lock*) my_malloc(sizeof(User_level_lock), + MYF(MY_WME|MY_THREAD_SPECIFIC)); + if (ull == NULL) { - ull->locked=1; - ull->set_thread(thd); - ull->thread_id= thd->thread_id; - thd->ull=ull; - error=0; - DBUG_PRINT("info", ("got the lock")); + thd->mdl_context.release_lock(ull_request.ticket); + DBUG_RETURN(0); } - mysql_mutex_unlock(&LOCK_user_locks); - mysql_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - mysql_mutex_unlock(&thd->mysys_var->mutex); + ull->lock= ull_request.ticket; + ull->refs= 1; + + if (my_hash_insert(&thd->ull_hash, (uchar*) ull)) + { + thd->mdl_context.release_lock(ull->lock); + my_free(ull); + DBUG_RETURN(0); + } + null_value= 0; - DBUG_RETURN(!error ? 1 : 0); + DBUG_RETURN(1); } @@ -4136,43 +4129,86 @@ longlong Item_func_get_lock::val_int() longlong Item_func_release_lock::val_int() { DBUG_ASSERT(fixed == 1); - String *res=args[0]->val_str(&value); - User_level_lock *ull; - longlong result; - THD *thd=current_thd; + String *res= args[0]->val_str(&value); + THD *thd= current_thd; DBUG_ENTER("Item_func_release_lock::val_int"); - if (!res || !res->length()) - { - null_value=1; + null_value= 1; + + if (!ull_name_ok(res)) DBUG_RETURN(0); - } + DBUG_PRINT("info", ("lock %.*s", res->length(), res->ptr())); - null_value=0; - result=0; - mysql_mutex_lock(&LOCK_user_locks); - if (!(ull= ((User_level_lock*) my_hash_search(&hash_user_locks, - (const uchar*) res->ptr(), - (size_t) res->length())))) + MDL_key ull_key; + ull_key.mdl_key_init(MDL_key::USER_LOCK, res->c_ptr_safe(), ""); + + User_level_lock *ull; + + if (!(ull= + (User_level_lock*) my_hash_search(&thd->ull_hash, + ull_key.ptr(), ull_key.length()))) { - null_value=1; + null_value= thd->mdl_context.get_lock_owner(&ull_key) == 0; + DBUG_RETURN(0); } - else + null_value= 0; + if (--ull->refs == 0) { - DBUG_PRINT("info", ("ull->locked=%d ull->thread=%lu thd=%lu", - (int) ull->locked, - (long)ull->thread_id, - (long)thd->thread_id)); - if (ull->locked && current_thd->thread_id == ull->thread_id) - { - DBUG_PRINT("info", ("release lock")); - result=1; // Release is ok - item_user_lock_release(ull); - thd->ull=0; - } + my_hash_delete(&thd->ull_hash, (uchar*) ull); + thd->mdl_context.release_lock(ull->lock); + my_free(ull); } - mysql_mutex_unlock(&LOCK_user_locks); - DBUG_RETURN(result); + DBUG_RETURN(1); +} + + +/** + Check a user level lock. + + Sets null_value=TRUE on error. + + @retval + 1 Available + @retval + 0 Already taken, or error +*/ + +longlong Item_func_is_free_lock::val_int() +{ + DBUG_ASSERT(fixed == 1); + String *res= args[0]->val_str(&value); + THD *thd= current_thd; + null_value= 1; + + if (!ull_name_ok(res)) + return 0; + + MDL_key ull_key; + ull_key.mdl_key_init(MDL_key::USER_LOCK, res->c_ptr_safe(), ""); + + null_value= 0; + return thd->mdl_context.get_lock_owner(&ull_key) == 0; +} + + +longlong Item_func_is_used_lock::val_int() +{ + DBUG_ASSERT(fixed == 1); + String *res= args[0]->val_str(&value); + THD *thd= current_thd; + null_value= 1; + + if (!ull_name_ok(res)) + return 0; + + MDL_key ull_key; + ull_key.mdl_key_init(MDL_key::USER_LOCK, res->c_ptr_safe(), ""); + ulong thread_id = thd->mdl_context.get_lock_owner(&ull_key); + if (thread_id == 0) + return 0; + + null_value= 0; + return thread_id; } @@ -4273,6 +4309,54 @@ void Item_func_benchmark::print(String *str, enum_query_type query_type) } +mysql_mutex_t LOCK_item_func_sleep; + +#ifdef HAVE_PSI_INTERFACE +static PSI_mutex_key key_LOCK_item_func_sleep; + +static PSI_mutex_info item_func_sleep_mutexes[]= +{ + { &key_LOCK_item_func_sleep, "LOCK_user_locks", PSI_FLAG_GLOBAL} +}; + + +static void init_item_func_sleep_psi_keys(void) +{ + const char* category= "sql"; + int count; + + if (PSI_server == NULL) + return; + + count= array_elements(item_func_sleep_mutexes); + PSI_server->register_mutex(category, item_func_sleep_mutexes, count); +} +#endif + +static bool item_func_sleep_inited= 0; + + +void item_func_sleep_init(void) +{ +#ifdef HAVE_PSI_INTERFACE + init_item_func_sleep_psi_keys(); +#endif + + mysql_mutex_init(key_LOCK_item_func_sleep, &LOCK_item_func_sleep, MY_MUTEX_INIT_SLOW); + item_func_sleep_inited= 1; +} + + +void item_func_sleep_free(void) +{ + if (item_func_sleep_inited) + { + item_func_sleep_inited= 0; + mysql_mutex_destroy(&LOCK_item_func_sleep); + } +} + + /** This function is just used to create tests with time gaps. */ longlong Item_func_sleep::val_int() @@ -4301,23 +4385,23 @@ longlong Item_func_sleep::val_int() timed_cond.set_timeout((ulonglong) (timeout * 1000000000.0)); mysql_cond_init(key_item_func_sleep_cond, &cond, NULL); - mysql_mutex_lock(&LOCK_user_locks); + mysql_mutex_lock(&LOCK_item_func_sleep); THD_STAGE_INFO(thd, stage_user_sleep); - thd->mysys_var->current_mutex= &LOCK_user_locks; + thd->mysys_var->current_mutex= &LOCK_item_func_sleep; thd->mysys_var->current_cond= &cond; error= 0; thd_wait_begin(thd, THD_WAIT_SLEEP); while (!thd->killed) { - error= timed_cond.wait(&cond, &LOCK_user_locks); + error= timed_cond.wait(&cond, &LOCK_item_func_sleep); if (error == ETIMEDOUT || error == ETIME) break; error= 0; } thd_wait_end(thd); - mysql_mutex_unlock(&LOCK_user_locks); + mysql_mutex_unlock(&LOCK_item_func_sleep); mysql_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; thd->mysys_var->current_cond= 0; @@ -4653,7 +4737,7 @@ double user_var_entry::val_real(bool *null_value) longlong user_var_entry::val_int(bool *null_value) const { if ((*null_value= (value == 0))) - return LL(0); + return 0; switch (type) { case REAL_RESULT: @@ -4677,7 +4761,7 @@ longlong user_var_entry::val_int(bool *null_value) const DBUG_ASSERT(0); // Impossible break; } - return LL(0); // Impossible + return 0; // Impossible } @@ -4815,7 +4899,7 @@ void Item_func_set_user_var::save_item_result(Item *item) { DBUG_ENTER("Item_func_set_user_var::save_item_result"); - switch (cached_result_type) { + switch (args[0]->result_type()) { case REAL_RESULT: save_result.vreal= item->val_result(); break; @@ -5170,7 +5254,7 @@ longlong Item_func_get_user_var::val_int() { DBUG_ASSERT(fixed == 1); if (!var_entry) - return LL(0); // No such variable + return 0; // No such variable return (var_entry->val_int(&null_value)); } @@ -5652,24 +5736,6 @@ enum_field_types Item_func_get_system_var::field_type() const } -/* - Uses var, var_type, component, cache_present, used_query_id, thd, - cached_llval, null_value, cached_null_value -*/ -#define get_sys_var_safe(type) \ -do { \ - type value; \ - mysql_mutex_lock(&LOCK_global_system_variables); \ - value= *(type*) var->value_ptr(thd, var_type, &component); \ - mysql_mutex_unlock(&LOCK_global_system_variables); \ - cache_present |= GET_SYS_VAR_CACHE_LONG; \ - used_query_id= thd->query_id; \ - cached_llval= null_value ? 0 : (longlong) value; \ - cached_null_value= null_value; \ - return cached_llval; \ -} while (0) - - longlong Item_func_get_system_var::val_int() { THD *thd= current_thd; @@ -5703,51 +5769,11 @@ longlong Item_func_get_system_var::val_int() } } - switch (var->show_type()) - { - case SHOW_SINT: get_sys_var_safe (int); - case SHOW_SLONG: get_sys_var_safe (long); - case SHOW_SLONGLONG:get_sys_var_safe (longlong); - case SHOW_UINT: get_sys_var_safe (uint); - case SHOW_ULONG: get_sys_var_safe (ulong); - case SHOW_ULONGLONG:get_sys_var_safe (ulonglong); - case SHOW_HA_ROWS: get_sys_var_safe (ha_rows); - case SHOW_BOOL: get_sys_var_safe (bool); - case SHOW_MY_BOOL: get_sys_var_safe (my_bool); - case SHOW_DOUBLE: - { - double dval= val_real(); - - used_query_id= thd->query_id; - cached_llval= (longlong) dval; - cache_present|= GET_SYS_VAR_CACHE_LONG; - return cached_llval; - } - case SHOW_CHAR: - case SHOW_CHAR_PTR: - case SHOW_LEX_STRING: - { - String *str_val= val_str(NULL); - - if (str_val && str_val->length()) - cached_llval= longlong_from_string_with_check (system_charset_info, - str_val->c_ptr(), - str_val->c_ptr() + - str_val->length()); - else - { - null_value= TRUE; - cached_llval= 0; - } - - cache_present|= GET_SYS_VAR_CACHE_LONG; - return cached_llval; - } - - default: - my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str); - return 0; // keep the compiler happy - } + cached_llval= var->val_int(&null_value, thd, var_type, &component); + cache_present |= GET_SYS_VAR_CACHE_LONG; + used_query_id= thd->query_id; + cached_null_value= null_value; + return cached_llval; } @@ -5780,61 +5806,10 @@ String* Item_func_get_system_var::val_str(String* str) } } - str= &cached_strval; - switch (var->show_type()) - { - case SHOW_CHAR: - case SHOW_CHAR_PTR: - case SHOW_LEX_STRING: - { - mysql_mutex_lock(&LOCK_global_system_variables); - char *cptr= var->show_type() == SHOW_CHAR ? - (char*) var->value_ptr(thd, var_type, &component) : - *(char**) var->value_ptr(thd, var_type, &component); - if (cptr) - { - size_t len= var->show_type() == SHOW_LEX_STRING ? - ((LEX_STRING*)(var->value_ptr(thd, var_type, &component)))->length : - strlen(cptr); - if (str->copy(cptr, len, collation.collation)) - { - null_value= TRUE; - str= NULL; - } - } - else - { - null_value= TRUE; - str= NULL; - } - mysql_mutex_unlock(&LOCK_global_system_variables); - break; - } - - case SHOW_SINT: - case SHOW_SLONG: - case SHOW_SLONGLONG: - case SHOW_UINT: - case SHOW_ULONG: - case SHOW_ULONGLONG: - case SHOW_HA_ROWS: - case SHOW_BOOL: - case SHOW_MY_BOOL: - str->set (val_int(), collation.collation); - break; - case SHOW_DOUBLE: - str->set_real (val_real(), decimals, collation.collation); - break; - - default: - my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str); - str= NULL; - break; - } - + str= var->val_str(&cached_strval, thd, var_type, &component); cache_present|= GET_SYS_VAR_CACHE_STRING; used_query_id= thd->query_id; - cached_null_value= null_value; + cached_null_value= null_value= !str; return str; } @@ -5872,58 +5847,11 @@ double Item_func_get_system_var::val_real() } } - switch (var->show_type()) - { - case SHOW_DOUBLE: - mysql_mutex_lock(&LOCK_global_system_variables); - cached_dval= *(double*) var->value_ptr(thd, var_type, &component); - mysql_mutex_unlock(&LOCK_global_system_variables); - used_query_id= thd->query_id; - cached_null_value= null_value; - if (null_value) - cached_dval= 0; - cache_present|= GET_SYS_VAR_CACHE_DOUBLE; - return cached_dval; - case SHOW_CHAR: - case SHOW_LEX_STRING: - case SHOW_CHAR_PTR: - { - mysql_mutex_lock(&LOCK_global_system_variables); - char *cptr= var->show_type() == SHOW_CHAR ? - (char*) var->value_ptr(thd, var_type, &component) : - *(char**) var->value_ptr(thd, var_type, &component); - if (cptr) - cached_dval= double_from_string_with_check (system_charset_info, - cptr, cptr + strlen (cptr)); - else - { - null_value= TRUE; - cached_dval= 0; - } - mysql_mutex_unlock(&LOCK_global_system_variables); - used_query_id= thd->query_id; - cached_null_value= null_value; - cache_present|= GET_SYS_VAR_CACHE_DOUBLE; - return cached_dval; - } - case SHOW_SINT: - case SHOW_SLONG: - case SHOW_SLONGLONG: - case SHOW_UINT: - case SHOW_ULONG: - case SHOW_ULONGLONG: - case SHOW_HA_ROWS: - case SHOW_BOOL: - case SHOW_MY_BOOL: - cached_dval= (double) val_int(); - cache_present|= GET_SYS_VAR_CACHE_DOUBLE; - used_query_id= thd->query_id; - cached_null_value= null_value; - return cached_dval; - default: - my_error(ER_VAR_CANT_BE_READ, MYF(0), var->name.str); - return 0; - } + cached_dval= var->val_real(&null_value, thd, var_type, &component); + cache_present |= GET_SYS_VAR_CACHE_DOUBLE; + used_query_id= thd->query_id; + cached_null_value= null_value; + return cached_dval; } @@ -6009,15 +5937,12 @@ void Item_func_match::init_search(bool no_order) { DBUG_ENTER("Item_func_match::init_search"); + if (!table->file->get_table()) // the handler isn't opened yet + DBUG_VOID_RETURN; + /* Check if init_search() has been called before */ if (ft_handler) { - /* - We should reset ft_handler as it is cleaned up - on destruction of FT_SELECT object - (necessary in case of re-execution of subquery). - TODO: FT_SELECT should not clean up ft_handler. - */ if (join_key) table->file->ft_handler= ft_handler; DBUG_VOID_RETURN; @@ -6026,10 +5951,10 @@ void Item_func_match::init_search(bool no_order) if (key == NO_SUCH_KEY) { List<Item> fields; - fields.push_back(new Item_string(" ",1, cmp_collation.collation)); - for (uint i=1; i < arg_count; i++) + fields.push_back(new Item_string(" ", 1, cmp_collation.collation)); + for (uint i= 1; i < arg_count; i++) fields.push_back(args[i]); - concat_ws=new Item_func_concat_ws(fields); + concat_ws= new Item_func_concat_ws(fields); /* Above function used only to get value and do not need fix_fields for it: Item_string - basic constant @@ -6041,10 +5966,10 @@ void Item_func_match::init_search(bool no_order) if (master) { - join_key=master->join_key=join_key|master->join_key; + join_key= master->join_key= join_key | master->join_key; master->init_search(no_order); - ft_handler=master->ft_handler; - join_key=master->join_key; + ft_handler= master->ft_handler; + join_key= master->join_key; DBUG_VOID_RETURN; } @@ -6054,7 +5979,7 @@ void Item_func_match::init_search(bool no_order) if (!(ft_tmp=key_item()->val_str(&value))) { ft_tmp= &value; - value.set("",0,cmp_collation.collation); + value.set("", 0, cmp_collation.collation); } if (ft_tmp->charset() != cmp_collation.collation) @@ -6067,7 +5992,11 @@ void Item_func_match::init_search(bool no_order) if (join_key && !no_order) flags|=FT_SORTED; - ft_handler=table->file->ft_init_ext(flags, key, ft_tmp); + + if (key != NO_SUCH_KEY) + THD_STAGE_INFO(table->in_use, stage_fulltext_initialization); + + ft_handler= table->file->ft_init_ext(flags, key, ft_tmp); if (join_key) table->file->ft_handler=ft_handler; @@ -6127,7 +6056,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) table=((Item_field *)item)->field->table; if (!(table->file->ha_table_flags() & HA_CAN_FULLTEXT)) { - my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0)); + my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0), table->file->table_type()); return 1; } table->fulltext_searched=1; @@ -6348,61 +6277,6 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, } -/** - Check a user level lock. - - Sets null_value=TRUE on error. - - @retval - 1 Available - @retval - 0 Already taken, or error -*/ - -longlong Item_func_is_free_lock::val_int() -{ - DBUG_ASSERT(fixed == 1); - String *res=args[0]->val_str(&value); - User_level_lock *ull; - - null_value=0; - if (!res || !res->length()) - { - null_value=1; - return 0; - } - - mysql_mutex_lock(&LOCK_user_locks); - ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), - (size_t) res->length()); - mysql_mutex_unlock(&LOCK_user_locks); - if (!ull || !ull->locked) - return 1; - return 0; -} - -longlong Item_func_is_used_lock::val_int() -{ - DBUG_ASSERT(fixed == 1); - String *res=args[0]->val_str(&value); - User_level_lock *ull; - - null_value=1; - if (!res || !res->length()) - return 0; - - mysql_mutex_lock(&LOCK_user_locks); - ull= (User_level_lock *) my_hash_search(&hash_user_locks, (uchar*) res->ptr(), - (size_t) res->length()); - mysql_mutex_unlock(&LOCK_user_locks); - if (!ull || !ull->locked) - return 0; - - null_value=0; - return ull->thread_id; -} - - longlong Item_func_row_count::val_int() { DBUG_ASSERT(fixed == 1); |